""" mbed SDK Copyright (c) 2011-2016 ARM Limited Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import re import shutil from os import remove from os.path import splitext, basename, exists from subprocess import Popen, PIPE from jinja2.exceptions import TemplateNotFound from tools.export.exporters import Exporter, apply_supported_whitelist from tools.targets import TARGET_MAP from tools.utils import NotSupportedException class CMake(Exporter): """Generic CMake template that mimics the behavior of the python build system """ TEMPLATE = 'CMakeLists.txt' MBED_CONFIG_HEADER_SUPPORTED = True PREPROCESS_ASM = False POST_BINARY_WHITELIST = set([ "MCU_NRF51Code.binary_hook", "TEENSY3_1Code.binary_hook", "LPCTargetCode.lpc_patch", "LPC4088Code.binary_hook" ]) @classmethod def is_target_supported(cls, target_name): target = TARGET_MAP[target_name] return apply_supported_whitelist( cls.TOOLCHAIN, cls.POST_BINARY_WHITELIST, target) def generate(self): """Generate the CMakefiles.txt """ self.resources.win_to_unix() # get all source files including headers, adding headers allows IDEs to detect which files # belong to the project, otherwise headers may be greyed out and not work with inspection # (that is true for CLion and definitely for Visual Code) allSourceFiles = set(self.resources.c_sources + self.resources.cpp_sources + self.resources.s_sources + self.resources.headers) # create a list of dependencies (mbed add ...) dependencies = [l[:-4] for l in self.resources.lib_refs] # separate the individual dependency source files into a map with the dep name as key and an array if files depSources = {re.sub(r'^[.]/', '', l): sorted([f for f in allSourceFiles if f.startswith(l)]) for l in dependencies} # delete dependencies that have no source files (may happen if a sub-dependency is ignored by .mbedignore) depSources = {k: v for k, v in depSources.items() if len(v) != 0} # remove all source files that ended up being part of one of the dependencies srcs = allSourceFiles for dep in depSources.values(): srcs.difference_update(dep) # additional libraries libraries = [self.prepare_lib(basename(lib)) for lib in self.resources.libraries] sys_libs = [self.prepare_sys_lib(lib) for lib in self.toolchain.sys_libs] ctx = { 'name': self.project_name, 'target': self.target, 'sources': sorted(srcs), 'dependencies': depSources, 'libraries': libraries, 'ld_sys_libs': sys_libs, 'include_paths': sorted(list(set(self.resources.inc_dirs))), 'library_paths': sorted(self.resources.lib_dirs), 'linker_script': self.resources.linker_script, 'hex_files': self.resources.hex_files, 'ar': basename(self.toolchain.ar), 'cc': basename(self.toolchain.cc[0]), 'cc_flags': " ".join(flag for flag in self.toolchain.cc[1:] if not flag == "-c"), 'cxx': basename(self.toolchain.cppc[0]), 'cxx_flags': " ".join(flag for flag in self.toolchain.cppc[1:] if not flag == "-c"), 'asm': basename(self.toolchain.asm[0]), 'asm_flags': " ".join(flag for flag in self.toolchain.asm[1:] if not flag == "-c"), 'symbols': sorted(self.toolchain.get_symbols()), 'ld': basename(self.toolchain.ld[0]), # fix the missing underscore '_' (see 'ld_flags': re.sub("--wrap,_(?!_)", "--wrap,__", " ".join(self.toolchain.ld[1:])), 'elf2bin': basename(self.toolchain.elf2bin), 'link_script_ext': self.toolchain.LINKER_EXT, 'link_script_option': self.LINK_SCRIPT_OPTION, 'user_library_flag': self.USER_LIBRARY_FLAG, 'needs_asm_preproc': self.PREPROCESS_ASM, } if hasattr(self.toolchain, "preproc"): ctx['pp'] = basename(self.toolchain.preproc[0]) ctx['pp_flags'] = " ".join(self.toolchain.preproc[1:] + self.toolchain.ld[1:]) else: ctx['pp'] = None ctx['pp_flags'] = None try: self.gen_file('cmake/%s.tmpl' % self.TEMPLATE, ctx, 'CMakeLists.txt') except TemplateNotFound: pass @staticmethod def build(project_name, log_name="build_log.txt", cleanup=True): """ Build Make project """ # > Make -j cmd = ["make", "-j"] # Build the project p = Popen(cmd, stdout=PIPE, stderr=PIPE) out, err = p.communicate() ret_code = p.returncode out_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n" out_string += out out_string += "=" * 10 + "STDERR" + "=" * 10 + "\n" out_string += err if ret_code == 0: out_string += "SUCCESS" else: out_string += "FAILURE" print out_string if log_name: # Write the output to the log file with open(log_name, 'w+') as f: f.write(out_string) # Cleanup the exported and built files if cleanup: remove("CMakeLists.txt") remove(log_name) # legacy .build directory cleaned if exists if exists('.build'): shutil.rmtree('.build') if exists('BUILD'): shutil.rmtree('BUILD') if ret_code != 0: # Seems like something went wrong. return -1 else: return 0 class GccArm(CMake): """GCC ARM specific cmake target""" NAME = 'CMake-GCC-ARM' TOOLCHAIN = "GCC_ARM" LINK_SCRIPT_OPTION = "-T" USER_LIBRARY_FLAG = "-L" @staticmethod def prepare_lib(libname): if "lib" == libname[:3]: libname = libname[3:-2] return "-l" + libname @staticmethod def prepare_sys_lib(libname): return "-l" + libname # class Arm(CMake): # """ARM Compiler generic cmake target""" # LINK_SCRIPT_OPTION = "--scatter" # USER_LIBRARY_FLAG = "--userlibpath " # # @staticmethod # def prepare_lib(libname): # return libname # # @staticmethod # def prepare_sys_lib(libname): # return libname # # def generate(self): # if self.resources.linker_script: # new_script = self.toolchain.correct_scatter_shebang( # self.resources.linker_script) # if new_script is not self.resources.linker_script: # self.resources.linker_script = new_script # self.generated_files.append(new_script) # return super(Arm, self).generate() # # # class Armc5(Arm): # """ARM Compiler 5 (armcc) specific makefile target""" # NAME = 'CMake-ARMc5' # TOOLCHAIN = "ARM" # PREPROCESS_ASM = True # # # class Armc6(Arm): # """ARM Compiler 6 (armclang) specific generic makefile target""" # NAME = 'CMake-ARMc6' # TOOLCHAIN = "ARMC6" # # # class IAR(CMake): # """IAR specific cmake target""" # NAME = 'CMake-IAR' # TOOLCHAIN = "IAR" # LINK_SCRIPT_OPTION = "--config" # USER_LIBRARY_FLAG = "-L" # # @staticmethod # def prepare_lib(libname): # if "lib" == libname[:3]: # libname = libname[3:] # return "-l" + splitext(libname)[0] # # @staticmethod # def prepare_sys_lib(libname): # if "lib" == libname[:3]: # libname = libname[3:] # return "-l" + splitext(libname)[0]