Ejemplo n.º 1
0
def main_bootstrap_build(args, input, state, output):
    try:
        print("")
        output.print_main_title()

        try_restore_previous_state(input, "n", state)
    
        target = select_target(input, state, output)

        Path("Build").mkdir(exist_ok=True)

        dependencies = Dependencies()
        dependencies.check(output)

        projects = Projects(target)

        projects.set_environment_variables(output)

        download_source_packages(projects, args.skip_downloads, input, state,
                                 output)

        compilers = Compilers(target)
        compiler = compilers.select_compiler(input, state, output)

        build_configuration = BuildConfiguration()
        build_configuration.select_configuration(target.architecture,
                                                 compiler, input, state)

        cmake = CMake(compiler.cmake_generator)
        cmake.install(target, state, output)

        codesmithymake = CodeSmithyMake(target.architecture)

        build_tools = BuildTools(cmake, compiler, codesmithymake)
        
        projects.build(build_tools, build_configuration,
                       input, state, output)

        print("")
        output.print_step_title("Running tests")
        if args.skip_tests:
            print("    Skipping tests")
        else:
            projects.test(compiler, build_configuration.architecture_dir_name,
                          input)
        output.next_step()

        print("")
        output.print_step_title("Setting up second-phase of bootstrap")
        second_phase_path = str(Path(os.getcwd()).parent) + \
                            "/SecondPhaseBootstrap"
        Path(second_phase_path).mkdir(exist_ok=True)
        print(second_phase_path)
        # TODO
        shutil.copyfile("Build/CodeSmithyIDE/CodeSmithy/Bin/x64/CodeSmithy.exe", second_phase_path + "/CodeSmithy.exe")
        output.next_step()
    except RuntimeError as error:
        print("")
        print("ERROR:", error)
        sys.exit(-1)
Ejemplo n.º 2
0
    def __init__(self, generatorInfo, rootDirectory, sourceDirectory, buildFolder):
        self.logger = logging.getLogger(__name__)
        self.cmake = CMake()
        self.generatorInfo = generatorInfo
        self.sourceDirectory = sourceDirectory
        self.rootDirectory = rootDirectory

        self.buildFolder = buildFolder
Ejemplo n.º 3
0
    def __init__(self, buildExecutor, generatorInfo, sourceDirectory,
                 buildFolder):
        self.logger = logging.getLogger(__name__)
        self.generatorInfo = generatorInfo
        self.sourceDirectory = sourceDirectory
        self.buildFolder = buildFolder
        self.buildExecutor = buildExecutor
        self.gradle = Gradle(sourceDirectory)
        self.cmake = CMake()

        self.androidBuildApiVersion = "28"
        self.androidBuildToolsVersion = "28.0.2"
        self.androidEmulatorApiVersion = "28"
Ejemplo n.º 4
0
def match_command_groups(contents, base_depth=0):
    revised_contents = []

    current = []
    group = None
    depth = base_depth

    for content in contents:
        if group is None:
            if content.__class__ == Command and content.command_name in ['if', 'foreach']:
                group = content
                depth = base_depth + 1
            else:
                revised_contents.append(content)
        else:
            if content.__class__ == Command:
                if content.command_name == group.command_name:
                    depth += 1
                elif content.command_name == 'end' + group.command_name:
                    depth -= 1
                    if depth == base_depth:
                        recursive_contents = match_command_groups(current, base_depth + 1)
                        sub = CMake(initial_contents=recursive_contents, depth=base_depth + 1)
                        cg = CommandGroup(group, sub, content)
                        revised_contents.append(cg)
                        group = None
                        current = []
                        continue
            current.append(content)

    # Only will happen if the tags don't match. Shouldn't happen, but resolve leftovers
    if len(current) > 0:
        revised_contents += current

    return revised_contents
Ejemplo n.º 5
0
class AndroidExecutor:
    def __init__(self, buildExecutor, generatorInfo, sourceDirectory,
                 buildFolder, rootPath):
        self.logger = logging.getLogger(__name__)
        self.generatorInfo = generatorInfo
        self.sourceDirectory = sourceDirectory
        self.buildFolder = buildFolder
        self.buildExecutor = buildExecutor
        self.gradle = Gradle(sourceDirectory)
        self.rootPath = rootPath
        self.cmake = CMake()

        self.androidBuildApiVersion = "28"
        self.androidBuildToolsVersion = "28.0.2"
        self.androidEmulatorApiVersion = "28"

    def buildTarget(self, configuration, args, target):
        androidAbi = self.getAndroidABIFromArch(configuration.arch)
        androidHome = self.getAndroidHome()
        buildDir = self.buildFolder.getBuildDir(configuration)

        if configuration.buildsystem == "AndroidStudio":
            self.buildTargetAndroidStudio(configuration, args, target,
                                          androidAbi, androidHome, buildDir)
        else:
            self.buildTargetMake(configuration, args, target)

    def buildTargetMake(self, configuration, args, target):
        buildExecutor = BuildExecutor(self.generatorInfo, self.rootPath,
                                      self.sourceDirectory, self.buildFolder)
        buildExecutor.buildTarget(configuration, args, target)

    def buildTargetAndroidStudio(self, configuration, args, target, androidAbi,
                                 androidHome, buildDir):

        gradlePath = self.gradle.getGradlePath()
        gradleWrapperPath = self.getBuildToolPath(buildDir, "gradlew")

        arguments = ["\"" + gradleWrapperPath + "\""]

        if target == "clean":
            arguments += ["clean"]
        else:
            if args.config == "Release":
                arguments += ["assembleRelease"]
            else:
                arguments += ["assembleDebug"]

        self.logger.debug("Starting: %s", arguments)

        exitCode = subprocess.call(" ".join(arguments),
                                   shell=True,
                                   cwd=buildDir,
                                   env=self.getToolEnv())
        if exitCode != 0:
            raise error.ToolFailedError("%s" % (arguments), exitCode)

    def build(self, configuration, args):
        self.buildTarget(configuration, args, None)

    def clean(self, configuration, args):
        self.buildTarget(configuration, args, "clean")

    def package(self, configuration, args):
        if configuration.buildsystem == "AndroidStudio":
            self.logger.critical(
                "Cannot build packages with Android Studio, use make instead")
        else:
            self.buildTarget(configuration, args, "package")

    def prepare(self, platformState, configuration, args):
        androidAbi = self.getAndroidABIFromArch(configuration.arch)
        androidHome = self.getAndroidHome()

        self.prepareAndroidEnvironment(configuration, args.accept_terms)

        buildDir = self.buildFolder.getBuildDir(configuration)

        if configuration.buildsystem == "AndroidStudio":
            self.prepareAndroidStudio(platformState, configuration, androidAbi,
                                      androidHome, buildDir, args)
        else:
            self.prepareMake(platformState, configuration, args, androidAbi,
                             androidHome, buildDir)

    def prepareMake(self, platformState, configuration, args, androidAbi,
                    androidHome, cmakeBuildDir):
        self.cmake.open(self.sourceDirectory, cmakeBuildDir, "Unix Makefiles")

        android_abi_arg = self.getAndroidABIFromArch(configuration.arch)
        if not android_abi_arg:
            raise error.InvalidArchitectureError(
                "No target architecture specified. The architecture parameter is required for makefile build systems."
            )

        cmakeArguments = [
            "-DCMAKE_TOOLCHAIN_FILE=%s/ndk-bundle/build/cmake/android.toolchain.cmake"
            % (androidHome),
            "-DANDROID_ABI=%s" % (android_abi_arg),
            "-DANDROID_NATIVE_API_LEVEL=%s" % (self.androidBuildApiVersion),
            "-DCMAKE_BUILD_TYPE=%s" % (configuration.config),
            "-DBDN_BUILD_TESTS=Off",
            "-DBDN_BUILD_EXAMPLES=Off",
        ]

        if args.cmake_option:
            for option in args.cmake_option:
                cmakeArguments += ["-D" + option]

        if args.package_generator:
            cmakeArguments += [
                "-DCPACK_GENERATOR=%s" % (args.package_generator)
            ]

        if args.package_folder:
            packageFolder = args.package_folder
            if not os.path.isabs(packageFolder):
                packageFolder = os.path.join(
                    self.buildFolder.getBaseBuildDir(), packageFolder)

            cmakeArguments += [
                "-DCPACK_OUTPUT_FILE_PREFIX=%s" % (packageFolder)
            ]

        self.logger.warning(
            "Disabling examples and tests, as we cannot build apk's yet.")

        self.logger.debug("Starting configure ...")
        self.logger.debug(" Source Directory: %s", self.sourceDirectory)
        self.logger.debug(" Output Directory: %s", cmakeBuildDir)
        self.logger.debug(" Config: %s", configuration.config)
        self.logger.debug(" Arguments: %s", cmakeArguments)
        self.logger.debug(" Generator: %s", "Unix Makefiles")

        self.cmake.configure(cmakeArguments)

        pass

    def prepareAndroidStudio(self, platformState, configuration, androidAbi,
                             androidHome, buildDir, args):
        gradlePath = self.gradle.getGradlePath()

        self.gradle.stop()

        tmpCMakeFolder = os.path.join(buildDir, "tmp-cmake-gen")

        makefile_android_abi = self.getAndroidABIFromArch(configuration.arch)
        if not makefile_android_abi:
            # If we target multiple architectures at the same time, we simply use x86 for the temporary
            # Makefile project we generate here (since makefiles support only one architecture).
            # Note that the makefile is only used temporarily to detect the available projects and is never
            # used to build anything.
            makefile_android_abi = "x86"

        self.cmake.open(self.sourceDirectory, tmpCMakeFolder, "Unix Makefiles")

        cmakeArguments = [
            "-DCMAKE_TOOLCHAIN_FILE=%s/ndk-bundle/build/cmake/android.toolchain.cmake"
            % (androidHome), "-DCMAKE_SYSTEM_NAME=Android",
            "-DANDROID_ABI=%s" % (makefile_android_abi),
            "-DANDROID_NATIVE_API_LEVEL=%s" % (self.androidBuildApiVersion),
            "-DBAUER_RUN=Yes"
        ]

        if sys.platform == 'win32':
            cmakeArguments += [
                "-DCMAKE_MAKE_PROGRAM=%s/ndk-bundle/prebuilt/windows-x86_64/bin/make.exe"
                % (androidHome)
            ]

        if args.cmake_option:
            for option in args.cmake_option:
                cmakeArguments += ["-D" + option]

        self.logger.debug("Starting configure ...")
        self.logger.debug(" Arguments: %s", cmakeArguments)
        self.logger.debug(" Generator: %s", "Unix Makefiles")

        self.cmake.configure(cmakeArguments)

        cmakeConfigurations = self.cmake.codeModel["configurations"]
        if len(cmakeConfigurations) != 1:
            raise Exception("Number of configurations is not 1!")

        target_dependencies = self.calculateDependencies(self.cmake.codeModel)

        config = cmakeConfigurations[0]
        project = config["main-project"]

        self.logger.debug("Found project: %s", project["name"])
        targetNames = []
        targets = []
        for target in project["targets"]:
            if target["type"] == "SHARED_LIBRARY" or target[
                    "type"] == "EXECUTABLE" or target[
                        "type"] == "STATIC_LIBRARY":
                self.logger.debug("Found target: %s", target["name"])
                targetNames += [target["name"]]
                targets += [target]

        project = {
            "name": project["name"],
            "sourceDirectory": project["sourceDirectory"],
            "targetNames": targetNames,
            "targets": targets
        }

        # Use external CMake for building native code (supported as of AndroidStudio 3.2)
        generator = AndroidStudioProjectGenerator(self.gradle, self.cmake,
                                                  buildDir,
                                                  self.androidBuildApiVersion)

        generator.generate(project, androidAbi, target_dependencies, args)

    def getToolEnv(self):
        toolEnv = os.environ
        toolEnv["ANDROID_HOME"] = self.getAndroidHome()
        return toolEnv

    def getAndroidHome(self):
        android_home_dir = os.environ.get("ANDROID_HOME")
        if not android_home_dir:
            if sys.platform.startswith("linux"):
                android_home_dir = os.path.expanduser("~/Android/Sdk")
                if os.path.exists(android_home_dir):
                    self.logger.info(
                        "Android home directory automatically detected as: %s",
                        android_home_dir)
                else:
                    android_home_dir = None

            if sys.platform == "darwin":
                android_home_dir = os.path.expanduser("~/Library/Android/sdk")

                if os.path.exists(android_home_dir):
                    self.logger.info(
                        "Android home directory automatically detected as: %s",
                        android_home_dir)
                else:
                    android_home_dir = None

            if sys.platform == "win32":
                android_home_dir = os.path.expanduser(
                    "~/AppData/Local/Android/SDK")

                if os.path.exists(android_home_dir):
                    self.logger.info(
                        "Android home directory automatically detected as: %s",
                        android_home_dir)
                else:
                    android_home_dir = None

        if not android_home_dir:
            raise Exception(
                "ANDROID_HOME environment variable is not set. Please point it to the root of the android SDK installation."
            )

        return android_home_dir.replace('\\', '/')

    def getAndroidABIFromArch(self, arch):
        if arch == "std":
            return None
        else:
            return arch

    def getAndroidABI(self, configuration):
        return self.getAndroidABIFromArch(configuration.arch)

    def getBuildToolPath(self, androidHome, tool):
        path = os.path.join(androidHome, tool)
        if sys.platform == "win32":
            if os.path.exists(path + ".bat"):
                path += ".bat"
            elif os.path.exists(path + ".exe"):
                path += ".exe"

        if not os.path.exists(path):
            raise Exception("Couldn't find %s" % (tool))

        return path

    def calculateDependencies(self, codeModel):
        cmakeConfigurations = codeModel["configurations"]
        if len(cmakeConfigurations) != 1:
            raise Exception("Number of configurations is not 1!")

        config = cmakeConfigurations[0]
        projects = []
        artifacts = {}

        for project in config["projects"]:
            for target in project["targets"]:
                if "artifacts" in target and target[
                        "type"] == "SHARED_LIBRARY" or target[
                            "type"] == "STATIC_LIBRARY":
                    artifacts[target["name"]] = []
                    for artifact in target["artifacts"]:
                        artifacts[target["name"]] += [
                            os.path.basename(artifact)
                        ]

        dependencies = {}

        for project in config["projects"]:
            for target in project["targets"]:
                dependencies[target["name"]] = []
                if "linkLibraries" in target:
                    for depname, artifactList in artifacts.items():
                        for artifact in artifactList:
                            if artifact in target["linkLibraries"]:
                                dependencies[target["name"]] += [depname]

        return dependencies

    def tryDetectAndroidCmakeComponentName(self, sdkManagerPath):

        command = '"%s" --list' % (sdkManagerPath)
        try:
            output = subprocess.check_output(command,
                                             shell=True,
                                             env=self.getToolEnv(),
                                             universal_newlines=True)
        except:
            self.logger.warning("Failed to get Android SDK module list")
            return None

        last_cmake_component_name = None
        for line in output.splitlines():
            line = line.strip()
            if line.startswith("cmake;"):
                last_cmake_component_name = line.partition(" ")[0]
                break

        return last_cmake_component_name

    def workaroundPlatformTools2903(self):
        try:
            androidHome = self.getAndroidHome()
            sdkManagerPath = self.getBuildToolPath(androidHome,
                                                   "tools/bin/sdkmanager")

            sdkManagerCommand = '"%s" --list' % (sdkManagerPath)
            output = subprocess.check_output(sdkManagerCommand,
                                             shell=True,
                                             env=self.getToolEnv())

            for line in output.splitlines():
                parts = line.decode('utf-8').split('|')
                if len(parts) == 3:
                    if parts[0].strip() == 'platform-tools':
                        version = parts[1].strip()
                        if version == '29.0.3':
                            self.logger.info(
                                "Since platform-tools 29.0.3 breaks debugging native apps, we manually download 29.0.2"
                            )
                            tf = tempfile.NamedTemporaryFile(mode='w+b',
                                                             delete=False)

                            sourceName = "https://dl.google.com/android/repository/platform-tools_r29.0.2-"
                            if "linux" in sys.platform:
                                sourceName += "linux"
                            elif sys.platform == "win32":
                                sourceName += "windows"
                            elif sys.platform == "darwin":
                                sourceName += "darwin"
                            sourceName += ".zip"

                            download_file(sourceName, tf.name)

                            zipf = MyZipFile(tf.name, 'r')
                            zipf.extractall(androidHome)
                            zipf.close()

                            return True
            return False
        except:
            return False

    def prepareAndroidEnvironment(self, configuration, accept_terms):
        self.logger.info("Preparing android environment...")
        androidAbi = self.getAndroidABIFromArch(configuration.arch)
        androidHome = self.getAndroidHome()
        sdkManagerPath = self.getBuildToolPath(androidHome,
                                               "tools/bin/sdkmanager")

        if accept_terms:
            self.logger.info(
                "Ensuring that all android license agreements are accepted ..."
            )

            licenseCall = subprocess.Popen('"%s" --licenses' % sdkManagerPath,
                                           shell=True,
                                           env=self.getToolEnv(),
                                           stdin=subprocess.PIPE)

            licenseInputData = ""
            for i in range(100):
                licenseInputData += "y\n"
            licenseCall.communicate(licenseInputData.encode('utf-8'))

            self.logger.info("Done updating licenses.")

        self.logger.info(
            "Ensuring that all necessary android packages are installed...")

        platformToolsPackageName = '"platform-tools"'

        if self.workaroundPlatformTools2903():
            platformToolsPackageName = ""

        sdkManagerCommand = '"%s" %s "ndk-bundle" "extras;android;m2repository" "extras;google;m2repository" "build-tools;%s" "platforms;android-%s"' % (
            sdkManagerPath, platformToolsPackageName,
            self.androidBuildToolsVersion, self.androidBuildApiVersion)

        cmakeComponentName = self.tryDetectAndroidCmakeComponentName(
            sdkManagerPath)
        if cmakeComponentName:
            sdkManagerCommand += ' "%s"' % cmakeComponentName

        try:
            subprocess.check_call(sdkManagerCommand,
                                  shell=True,
                                  env=self.getToolEnv())
        except:
            self.logger.warning(
                "Failed getting emulator, you will not be able to 'run' this configuration"
            )

        self.logger.info("Done updating packages.")
Ejemplo n.º 6
0
class BuildExecutor:
    def __init__(self, generatorInfo, rootDirectory, sourceDirectory,
                 buildFolder):
        self.logger = logging.getLogger(__name__)
        self.cmake = CMake()
        self.generatorInfo = generatorInfo
        self.sourceDirectory = sourceDirectory
        self.rootDirectory = rootDirectory

        self.buildFolder = buildFolder

    def build(self, configuration, args):
        self.buildTarget(configuration, args, args.target)

    def clean(self, configuration, args):
        self.buildTarget(configuration, args, "clean")

    def package(self, configuration, args):
        self.buildTarget(configuration, args, "package")

    def buildTarget(self, configuration, args, target):
        configs = [configuration.config]

        if args.config != None:
            configs = [args.config]

        if target == None and args.target != None:
            target = args.target

        isSingleConfigBuildSystem = self.generatorInfo.isSingleConfigBuildSystem(
            configuration.buildsystem)

        if not isSingleConfigBuildSystem and args.config == None:
            configs = []
            for cmakeConfiguration in self.cmake.codeModel["configurations"]:
                configs += [cmakeConfiguration["name"]]

        for config in configs:
            buildDirectory = self.buildFolder.getBuildDir(configuration)
            commandArguments = [
                "\"%s\"" % self.cmake.cmakeExecutable, "--build",
                "\"%s\"" % buildDirectory
            ]

            if target:
                commandArguments += ["--target", target]

            if not isSingleConfigBuildSystem:
                commandArguments += ["--config", config]

            if args.jobs != None:
                generatorName = self.generatorInfo.getCMakeGeneratorName(
                    configuration.buildsystem)
                if "Visual Studio" in generatorName:
                    os.environ["CL"] = "/MP" + args.jobs
                elif "Xcode" in generatorName:
                    pass  # Can' specify multicore via command line :(
                else:
                    commandArguments += ["--", "-j%s" % (args.jobs)]

            commandLine = " ".join(commandArguments)
            self.logger.info("Calling: %s", commandLine)

            exitCode = subprocess.call(commandLine,
                                       shell=True,
                                       cwd=buildDirectory)
            if exitCode != 0:
                raise error.ToolFailedError(commandLine, exitCode)

    def prepare(self, platformState, configuration, args):
        self.logger.debug("prepare(%s)", configuration)

        cmakeBuildDir = self.buildFolder.getBuildDir(configuration)

        toolChainFileName = None
        needsCleanBuildDir = False
        cmakeEnvironment = ""
        cmakeArch = configuration.arch
        cmakeArguments = []

        self.generatorInfo.ensureHaveCmake()

        generatorName = self.generatorInfo.getCMakeGeneratorName(
            configuration.buildsystem)

        commandIsInQuote = False

        if args.package_generator:
            cmakeArguments += [
                "-DCPACK_GENERATOR=%s" % (args.package_generator)
            ]

        if args.package_folder:
            packageFolder = args.package_folder
            if not os.path.isabs(packageFolder):
                packageFolder = os.path.join(
                    self.buildFolder.getBaseBuildDir(), packageFolder)

            cmakeArguments += [
                "-DCPACK_OUTPUT_FILE_PREFIX=%s" % (packageFolder)
            ]

        if configuration.platform == "mac":
            if configuration.arch != "std":
                raise error.InvalidArchitectureError(arch)

            if args.macos_sdk_path:
                cmakeArguments.extend(
                    ["-DCMAKE_OSX_SYSROOT=%s" % (args.macos_sdk_path)])
            if args.macos_min_version:
                cmakeArguments.extend([
                    "-DCMAKE_OSX_DEPLOYMENT_TARGET=%s" %
                    (args.macos_min_version)
                ])

        elif configuration.platform == "ios":
            if generatorName == 'Xcode' and configuration.arch == "std":
                toolChainFileName = "ios.xcode.toolchain.cmake"
                xcodeDevPath = subprocess.check_output(
                    ['xcode-select', '-p']).decode("utf-8").strip()
                whichCxx = subprocess.check_output(['which', 'c++'
                                                    ]).decode("utf-8").strip()

                self.logger.debug("Environment info:")
                self.logger.debug('\t"xcode-select -p": "%s"' % (xcodeDevPath))
                self.logger.debug('\t"which c++": "%s"' % (whichCxx))
                expected_clangxx_location = os.path.join(
                    xcodeDevPath,
                    "Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++")

                if not os.path.isfile(expected_clangxx_location):
                    self.logger.warning(
                        'Expected file "%s" to exist but it did not' %
                        (expected_clangxx_location))

            else:
                if configuration.arch == "std" or configuration.arch == "simulator":
                    cmakeArguments.extend(["-DIOS_PLATFORM=SIMULATOR64"])
                elif configuration.arch == "device":
                    cmakeArguments.extend(["-DIOS_PLATFORM=OS64"])
                else:
                    raise error.InvalidArchitectureError(arch)

                toolChainFileName = "ios.make.toolchain.cmake"

        if toolChainFileName:
            toolChainFilePath = os.path.join(self.rootDirectory,
                                             "cmake/toolchains",
                                             toolChainFileName)

            if not os.path.isfile(toolChainFilePath):
                self.logger.error(
                    "Required CMake toolchain file not found: %s",
                    toolChainFilePath)
                return 5

            cmakeArguments += ["-DCMAKE_TOOLCHAIN_FILE=" + toolChainFilePath]

        if configuration.config:
            cmakeArguments += ["-DCMAKE_BUILD_TYPE=" + configuration.config]

        if cmakeArch:
            cmakeArguments += ["-A " + cmakeArch]

        if args.cmake_option:
            for option in args.cmake_option:
                cmakeArguments += ["-D" + option]

        if needsCleanBuildDir:
            shutil.rmtree(cmakeBuildDir)

        self.cmake.open(self.sourceDirectory,
                        cmakeBuildDir,
                        generatorName,
                        extraGeneratorName="",
                        extraEnv=cmakeEnvironment)

        self.logger.debug("Starting configure ...")
        self.logger.debug(" Source Directory: %s", self.sourceDirectory)
        self.logger.debug(" Output Directory: %s", cmakeBuildDir)
        self.logger.debug(" Arguments: %s", cmakeArguments)
        self.logger.debug(" Generator: %s", generatorName)

        self.cmake.configure(cmakeArguments)
Ejemplo n.º 7
0
    def init(self):
        """ this method is called right after reading the configuration file.
            so, it is useful for initializing variables that depend on the
            installation mode or anything that depends on user changes in the
            configuration file """

        if (os.system("which which > /dev/null 2>&1") != 0):
            print "\"which\" is not installed on your system!!"
            sys.exit(1)

        t = time.gmtime()

        # save installation time to variable
        self.time = str(t[0]) + "-" + str(t[1]) + "-" + str(t[2]) + "_" + str(
            t[3]) + "-" + str(t[4])
        self.ctime = time.ctime()

        self.logfile = self.logsdir + self.config_file_prefix + "-" + self.time + ".log"

        # auto detect modules
        if (self.module("Java") == None):
            auto_java = Java()
            if (auto_java.autoDetected):
                self.autoModules.append(auto_java)
        if (self.module("QT") == None):
            auto_qt = QT()
            if (auto_qt.autoDetected):
                self.autoModules.append(auto_qt)
        if (self.module("CMake") == None):
            auto_cmake = CMake()
            if (auto_cmake.autoDetected):
                self.autoModules.append(auto_cmake)

        # initialize cmake supported modules
        for mod in self.modules:
            if (mod.hasCMakeFindSupport):
                self.cmakeSupportedMods.append(mod.name)

        # initialize each module
        print "+ Initialize modules..."
        for mod in self.modules:
            mod.init()

        print "\n+ Check for previous installations...\n"
        for mod in self.modules:
            mod.checkInstallConsistency()

        # skip dependencies for downloading only
        if (self.downloadOnly):
            return

        print "\n+ Dependencies Pre-Check..."
        for mod in self.modules:
            mod.preCheckDeps()

        print "\n+ Dependencies Check..."
        PkgUpdated = True
        while PkgUpdated:
            PkgUpdated = False

            for mod in self.modules:
                mod.checkRequiredDependencies()

            for mod in self.modules:
                mod.checkOptionalDependencies()

            for mod in self.modules:
                if (not mod.checkDeps()):
                    PkgUpdated = True

        print "\n+ Dependencies Post-Check..."
        for mod in self.modules:
            mod.postCheckDeps()

        print
Ejemplo n.º 8
0
class AndroidExecutor:
    def __init__(self, buildExecutor, generatorInfo, sourceDirectory,
                 buildFolder):
        self.logger = logging.getLogger(__name__)
        self.generatorInfo = generatorInfo
        self.sourceDirectory = sourceDirectory
        self.buildFolder = buildFolder
        self.buildExecutor = buildExecutor
        self.gradle = Gradle(sourceDirectory)
        self.cmake = CMake()

        self.androidBuildApiVersion = "28"
        self.androidBuildToolsVersion = "28.0.2"
        self.androidEmulatorApiVersion = "28"

    def buildTarget(self, configuration, args, target):
        androidAbi = self.getAndroidABIFromArch(configuration.arch)
        androidHome = self.getAndroidHome()
        buildDir = self.buildFolder.getBuildDir(configuration)

        if configuration.buildsystem == "AndroidStudio":
            self.buildTargetAndroidStudio(configuration, args, target,
                                          androidAbi, androidHome, buildDir)
        else:
            self.buildTargetMake(configuration, args, target)

    def buildTargetMake(self, configuration, args, target):
        buildExecutor = BuildExecutor(self.generatorInfo, self.sourceDirectory,
                                      self.buildFolder)
        buildExecutor.buildTarget(configuration, args, target)

    def buildTargetAndroidStudio(self, configuration, args, target, androidAbi,
                                 androidHome, buildDir):

        gradlePath = self.gradle.getGradlePath()
        gradleWrapperPath = self.getBuildToolPath(buildDir, "gradlew")

        arguments = ["\"" + gradleWrapperPath + "\""]

        if target == "clean":
            arguments += ["clean"]
        else:
            if args.config == "Release":
                arguments += ["assembleRelease"]
            else:
                arguments += ["assembleDebug"]

        self.logger.debug("Starting: %s", arguments)

        exitCode = subprocess.call(" ".join(arguments),
                                   shell=True,
                                   cwd=buildDir,
                                   env=self.getToolEnv())
        if exitCode != 0:
            raise error.ToolFailedError("%s" % (arguments), exitCode)

    def build(self, configuration, args):
        self.buildTarget(configuration, args, None)

    def clean(self, configuration, args):
        self.buildTarget(configuration, args, "clean")

    def package(self, configuration, args):
        if configuration.buildsystem == "AndroidStudio":
            self.logger.critical(
                "Cannot build packages with Android Studio, use make instead")
        else:
            self.buildTarget(configuration, args, "package")

    def prepare(self, platformState, configuration, args):
        androidAbi = self.getAndroidABIFromArch(configuration.arch)
        androidHome = self.getAndroidHome()

        self.prepareAndroidEnvironment(configuration, args.accept_terms)

        buildDir = self.buildFolder.getBuildDir(configuration)

        if configuration.buildsystem == "AndroidStudio":
            self.prepareAndroidStudio(platformState, configuration, androidAbi,
                                      androidHome, buildDir)
        else:
            self.prepareMake(platformState, configuration, args, androidAbi,
                             androidHome, buildDir)

    def prepareMake(self, platformState, configuration, args, androidAbi,
                    androidHome, cmakeBuildDir):
        self.cmake.open(self.sourceDirectory, cmakeBuildDir, "Unix Makefiles")

        android_abi_arg = self.getAndroidABIFromArch(configuration.arch)
        if not android_abi_arg:
            raise error.InvalidArchitectureError(
                "No target architecture specified. The architecture parameter is required for makefile build systems."
            )

        cmakeArguments = [
            "-DCMAKE_TOOLCHAIN_FILE=%s/ndk-bundle/build/cmake/android.toolchain.cmake"
            % (androidHome),
            "-DANDROID_ABI=%s" % (android_abi_arg),
            "-DANDROID_NATIVE_API_LEVEL=%s" % (self.androidBuildApiVersion),
            "-DCMAKE_BUILD_TYPE=%s" % (configuration.config),
            "-DBDN_BUILD_TESTS=Off",
            "-DBDN_BUILD_EXAMPLES=Off",
        ]

        if args.package_generator:
            cmakeArguments += [
                "-DCPACK_GENERATOR=%s" % (args.package_generator)
            ]

        if args.package_folder:
            packageFolder = args.package_folder
            if not os.path.isabs(packageFolder):
                packageFolder = os.path.join(
                    self.buildFolder.getBaseBuildDir(), packageFolder)

            cmakeArguments += [
                "-DCPACK_OUTPUT_FILE_PREFIX=%s" % (packageFolder)
            ]

        self.logger.warning(
            "Disabling examples and tests, as we cannot build apk's yet.")

        self.logger.debug("Starting configure ...")
        self.logger.debug(" Source Directory: %s", self.sourceDirectory)
        self.logger.debug(" Output Directory: %s", cmakeBuildDir)
        self.logger.debug(" Config: %s", configuration.config)
        self.logger.debug(" Arguments: %s", cmakeArguments)
        self.logger.debug(" Generator: %s", "Unix Makefiles")

        self.cmake.configure(cmakeArguments)

        pass

    def prepareAndroidStudio(self, platformState, configuration, androidAbi,
                             androidHome, buildDir):
        gradlePath = self.gradle.getGradlePath()

        self.gradle.stop()

        tmpCMakeFolder = os.path.join(buildDir, "tmp-cmake-gen")

        makefile_android_abi = self.getAndroidABIFromArch(configuration.arch)
        if not makefile_android_abi:
            # If we target multiple architectures at the same time then we simply use x86 for the temporary
            # Makefile project we generate here (since makefiles support only one architecture).
            # Note that the makefile is only used temporarily to detect the available projects and is never
            # used to build anything.
            makefile_android_abi = "x86"

        self.cmake.open(self.sourceDirectory, tmpCMakeFolder, "Unix Makefiles")

        cmakeArguments = [
            "-DCMAKE_TOOLCHAIN_FILE=%s/ndk-bundle/build/cmake/android.toolchain.cmake"
            % (androidHome), "-DCMAKE_SYSTEM_NAME=Android",
            "-DANDROID_ABI=%s" % (makefile_android_abi),
            "-DANDROID_NATIVE_API_LEVEL=%s" % (self.androidBuildApiVersion),
            "-DBAUER_RUN=Yes"
        ]

        if sys.platform == 'win32':
            cmakeArguments += [
                "-DCMAKE_MAKE_PROGRAM=%s/ndk-bundle/prebuilt/windows-x86_64/bin/make.exe"
                % (androidHome)
            ]

        self.logger.debug("Starting configure ...")
        self.logger.debug(" Arguments: %s", cmakeArguments)
        self.logger.debug(" Generator: %s", "Unix Makefiles")

        self.cmake.configure(cmakeArguments)

        cmakeConfigurations = self.cmake.codeModel["configurations"]
        if len(cmakeConfigurations) != 1:
            raise Exception("Number of configurations is not 1!")

        targetDependencies = self.calculateDependencies(self.cmake.codeModel)

        config = cmakeConfigurations[0]
        projects = []
        for project in config["projects"]:
            self.logger.debug("Found project: %s", project["name"])
            #projects += [project]
            targetNames = []
            targets = []
            for target in project["targets"]:
                if target["type"] == "SHARED_LIBRARY" or target[
                        "type"] == "EXECUTABLE" or target[
                            "type"] == "STATIC_LIBRARY":
                    self.logger.debug("Found target: %s", target["name"])
                    targetNames += [target["name"]]
                    targets += [target]

            projects += [{
                "name": project["name"],
                "sourceDirectory": project["sourceDirectory"],
                "targetNames": targetNames,
                "targets": targets
            }]

        # The way Android Studio builds projects with native code has changed
        # quite a bit over time. It used to be very messy, requiring experimental
        # plugins to work properly.
        # Since AndroidStudio 3.0 this has changed and there is a "standard" way
        # to do this. AndroidStudio now includes a custom, forked CMake
        # that actually works - and this builds the native code side.
        # We only support the new style projects now (see git history if
        # you want to know what it used to look like).

        generator = AndroidStudioProjectGenerator(self.gradle, buildDir,
                                                  self.androidBuildApiVersion)

        for project in projects:
            self.logger.debug("Generating project %s with targets: %s",
                              project["name"], project["targetNames"])
            generator.generateTopLevelProject(project["targetNames"])

            for target in project["targets"]:
                targetName = target["name"]

                rootCMakeFile = os.path.join(project["sourceDirectory"],
                                             "CMakeLists.txt").replace(
                                                 '\\', '/')

                generator.generateModule(
                    packageId="io.boden.android.%s" % (targetName),
                    cmakeTargetName=targetName,
                    targetSourceDirectory=target["sourceDirectory"],
                    userFriendlyTargetName=targetName,
                    dependencyList=targetDependencies[targetName],
                    isLibrary=target["type"] == "SHARED_LIBRARY",
                    android_abi=androidAbi,
                    rootCMakeFile=rootCMakeFile)

            break

        # At the time of this writing, Android Studio will not detect when new source files
        # have been added (even if we do a gradle sync, syncs on the cmake file, etc.).
        # To force re-detection of that we delete the .idea folder.
        idea_dir = os.path.join(buildDir, ".idea")
        if os.path.exists(idea_dir):
            self.logger.info(
                "Deleting .idea folder in build dir to force re-detection of files."
            )
            shutil.rmtree(idea_dir)

    def getToolEnv(self):
        toolEnv = os.environ
        toolEnv["ANDROID_HOME"] = self.getAndroidHome()
        return toolEnv

    def getAndroidHome(self):
        android_home_dir = os.environ.get("ANDROID_HOME")
        if not android_home_dir:
            if sys.platform.startswith("linux"):
                android_home_dir = os.path.expanduser("~/Android/Sdk")
                if os.path.exists(android_home_dir):
                    self.logger.info(
                        "Android home directory automatically detected as: %s",
                        android_home_dir)
                else:
                    android_home_dir = None

            if sys.platform == "darwin":
                android_home_dir = os.path.expanduser("~/Library/Android/sdk")

                if os.path.exists(android_home_dir):
                    self.logger.info(
                        "Android home directory automatically detected as: %s",
                        android_home_dir)
                else:
                    android_home_dir = None

            if sys.platform == "win32":
                android_home_dir = os.path.expanduser(
                    "~/AppData/Local/Android/SDK")

                if os.path.exists(android_home_dir):
                    self.logger.info(
                        "Android home directory automatically detected as: %s",
                        android_home_dir)
                else:
                    android_home_dir = None

        if not android_home_dir:
            raise Exception(
                "ANDROID_HOME environment variable is not set. Please point it to the root of the android SDK installation."
            )

        return android_home_dir.replace('\\', '/')

    def getAndroidABIFromArch(self, arch):
        if arch == "std":
            return None
        else:
            return arch

    def getAndroidABI(self, configuration):
        return self.getAndroidABIFromArch(configuration.arch)

    def getBuildToolPath(self, androidHome, tool):
        path = os.path.join(androidHome, tool)
        if sys.platform == "win32":
            if os.path.exists(path + ".bat"):
                path += ".bat"
            elif os.path.exists(path + ".exe"):
                path += ".exe"

        if not os.path.exists(path):
            raise Exception("Couldn't find %s" % (tool))

        return path

    def calculateDependencies(self, codeModel):
        cmakeConfigurations = codeModel["configurations"]
        if len(cmakeConfigurations) != 1:
            raise Exception("Number of configurations is not 1!")

        config = cmakeConfigurations[0]
        projects = []
        artifacts = {}

        for project in config["projects"]:
            for target in project["targets"]:
                if "artifacts" in target and target[
                        "type"] == "SHARED_LIBRARY" or target[
                            "type"] == "STATIC_LIBRARY":
                    artifacts[target["name"]] = []
                    for artifact in target["artifacts"]:
                        artifacts[target["name"]] += [
                            os.path.basename(artifact)
                        ]

        dependencies = {}

        for project in config["projects"]:
            for target in project["targets"]:
                dependencies[target["name"]] = []
                if "linkLibraries" in target:
                    for depname, artifactList in artifacts.items():
                        for artifact in artifactList:
                            if artifact in target["linkLibraries"]:
                                dependencies[target["name"]] += [depname]

        return dependencies

    def tryDetectAndroidCmakeComponentName(self, sdkManagerPath):

        command = '"%s" --list' % (sdkManagerPath)
        try:
            output = subprocess.check_output(command,
                                             shell=True,
                                             env=self.getToolEnv(),
                                             universal_newlines=True)
        except:
            self.logger.warning("Failed to get Android SDK module list")
            return None

        last_cmake_component_name = None
        for line in output.splitlines():
            line = line.strip()
            if line.startswith("cmake;"):
                last_cmake_component_name = line.partition(" ")[0]

        return last_cmake_component_name

    def prepareAndroidEnvironment(self, configuration, accept_terms):
        self.logger.info("Preparing android environment...")
        androidAbi = self.getAndroidABIFromArch(configuration.arch)
        androidHome = self.getAndroidHome()
        sdkManagerPath = self.getBuildToolPath(androidHome,
                                               "tools/bin/sdkmanager")

        if accept_terms:
            self.logger.info(
                "Ensuring that all android license agreements are accepted ..."
            )

            licenseCall = subprocess.Popen('"%s" --licenses' % sdkManagerPath,
                                           shell=True,
                                           env=self.getToolEnv(),
                                           stdin=subprocess.PIPE)

            licenseInputData = ""
            for i in range(100):
                licenseInputData += "y\n"
            licenseCall.communicate(licenseInputData.encode('utf-8'))

            self.logger.info("Done updating licenses.")

        self.logger.info(
            "Ensuring that all necessary android packages are installed...")

        sdkManagerCommand = '"%s" "platform-tools" "ndk-bundle" "extras;android;m2repository" "extras;google;m2repository" "build-tools;%s" "platforms;android-%s"' % (
            sdkManagerPath, self.androidBuildToolsVersion,
            self.androidBuildApiVersion)

        cmakeComponentName = self.tryDetectAndroidCmakeComponentName(
            sdkManagerPath)
        if cmakeComponentName:
            sdkManagerCommand += ' "%s"' % cmakeComponentName

        try:
            subprocess.check_call(sdkManagerCommand,
                                  shell=True,
                                  env=self.getToolEnv())
        except:
            self.logger.warning(
                "Failed getting emulator, you will not be able to 'run' this configuration"
            )

        self.logger.info("Done updating packages.")
Ejemplo n.º 9
0
#!/usr/bin/python
import os
import sys
from cmake import CMake

if len(sys.argv) < 2:
    print "usage: pycmake <srcdir>"
    sys.exit(0)

cmake = CMake(sys.argv[1], '.')
cmake.generate()
Ejemplo n.º 10
0
def parse_file(filename):
    with open(filename) as f:
        s = f.read()
        return CMake(file_path=filename, initial_contents=parse_commands(s))
Ejemplo n.º 11
0
def parse_argument():
    """
    Main script : define arguments and send to convertdata.

    """

    data = {
        'vcxproj': None,
        'cmake': None,
        'additional_code': None,
        'includes': None,
        'dependencies': None,
        'cmake_output': None,
        'data': None
    }

    # Init parser
    parser = argparse.ArgumentParser(
        description='Convert file.vcxproj to CMakelists.txt')
    parser.add_argument('-p',
                        help='absolute or relative path of a file.vcxproj')
    parser.add_argument('-o', help='define output.')
    parser.add_argument(
        '-a',
        help='import cmake code from file.cmake to your final CMakeLists.txt')
    parser.add_argument(
        '-D',
        help='replace dependencies found in .vcxproj, separated by colons.')
    parser.add_argument('-O',
                        help='define output of artefact produces by CMake.')
    parser.add_argument(
        '-i',
        help='add include directories in CMakeLists.txt. Default : False')

    # Get args
    args = parser.parse_args()

    # Vcxproj Path
    if args.p is not None:
        temp_path = os.path.splitext(args.p)
        if temp_path[1] == '.vcxproj':
            send('Project to convert = ' + args.p, '')
            project = Vcxproj()
            project.create_data(args.p)
            data['vcxproj'] = project.vcxproj
        else:
            send(
                'This file is not a ".vcxproj". Be sure you give the right file',
                'error')
            exit(1)

    # CMakeLists.txt output
    if args.o is not None:
        cmakelists = CMake()
        if os.path.exists(args.o):
            cmakelists.create_cmake(args.o)
            data['cmake'] = cmakelists.cmake
        else:
            send(
                'This path does not exist. CMakeList.txt will be generated in current directory.',
                'error')
            cmakelists.create_cmake()
        data['cmake'] = cmakelists.cmake
    else:
        cmakelists = CMake()
        cmakelists.create_cmake()
        data['cmake'] = cmakelists.cmake

    # CMake additional Code
    if args.a is not None:
        data['additional_code'] = args.a

    # If replace Dependencies
    if args.D is not None:
        data['dependencies'] = args.D.split(':')

    # Define Output of CMake artefact
    if args.O is not None:
        data['cmake_output'] = args.O

    # Add include directories found in vcxproj
    if args.i is not None:
        if args.i == 'True':
            data['includes'] = True

    # Give all to class: conversata
    all_data = ConvertData(data)
    all_data.create_data()