diff --git a/project_generator/templates/makefile.tmpl b/project_generator/templates/makefile.tmpl index 67810be0..e384e23e 100644 --- a/project_generator/templates/makefile.tmpl +++ b/project_generator/templates/makefile.tmpl @@ -15,6 +15,8 @@ # This project was exported via the project generator. More information https://github.com/project-generator/project_generator +.SUFFIXES: . + CPU = {{core}} # toolchain specific @@ -41,6 +43,7 @@ TARGET_EXT = .a {% endif %} LD_SCRIPT = {{linker_file}} +VPATH += {{output_dir.rel_path}} CC_SYMBOLS = {% for symbol in macros %} -D{{symbol}} {% endfor %} ASM_SYMBOLS = {% block ASM_SYMBOLS %}{% endblock %} @@ -76,7 +79,7 @@ C_FLAGS = {% for option in c_flags %} {{option}} {% endfor %} CXX_FLAGS = {% for option in cxx_flags %} {{option}} {% endfor %} ASM_FLAGS = {% for option in asm_flags %} {{option}} {% endfor %} -CFLAGS = $(C_FLAGS) $(INC_DIRS_F) -c $(CC_SYMBOLS) +CFLAGS += $(C_FLAGS) $(INC_DIRS_F) -c $(CC_SYMBOLS) CXXFLAGS = $(CXX_FLAGS) $(INC_DIRS_F) -c $(CC_SYMBOLS) ASFLAGS = $(ASM_FLAGS) $(INC_DIRS_F) -c $(ASM_SYMBOLS) @@ -84,8 +87,6 @@ ASFLAGS = $(ASM_FLAGS) $(INC_DIRS_F) -c $(ASM_SYMBOLS) LD_OPTIONS += {% for option in ld_flags %} {{option}} {% endfor %} LD_OPTIONS += {% block LD_OPTIONS %}{% endblock %} -OBJCPFLAGS = -O ihex - ARFLAGS = cr ifeq ($(OS),Windows_NT) @@ -95,34 +96,32 @@ else endif C_SRCS := {% for file in source_files_c %} {{file}} {% endfor %} -C_OBJS := $(patsubst %.c,$(OBJ_FOLDER)%.o,$(notdir $(C_SRCS))) +C_OBJS := $(patsubst %.c,$(OBJ_FOLDER)%.o,$(C_SRCS)) CPP_SRCS := {% for file in source_files_cpp %} {{file}} {% endfor %} -CPP_OBJS := $(patsubst %.cpp,$(OBJ_FOLDER)%.o,$(notdir $(CPP_SRCS))) +CPP_OBJS := $(patsubst %.cpp,$(OBJ_FOLDER)%.o,$(CPP_SRCS)) S_SRCS := {% for file in source_files_s %} {{file}} {% endfor %} -S_OBJS = $(patsubst %.s,$(OBJ_FOLDER)%.o,$(filter %.s,$(notdir $(S_SRCS)))) -S_OBJS += $(patsubst %.S,$(OBJ_FOLDER)%.o,$(filter %.S,$(notdir $(S_SRCS)))) +S_OBJS = $(patsubst %.s,$(OBJ_FOLDER)%.o,$(filter %.s,$(S_SRCS))) +S_OBJS += $(patsubst %.S,$(OBJ_FOLDER)%.o,$(filter %.S,$(S_SRCS))) O_OBJS := {% for file in source_files_obj %} {{file}} {% endfor %} -VPATH := $(SRC_DIRS) - -$(OBJ_FOLDER)%.o : %.c +$(OBJ_FOLDER)%.o : %.c | create_outputdir @echo 'Building file: $(@F)' @echo 'Invoking: MCU C Compiler' $(CC) $(CFLAGS) $(COMMON_FLAGS) $< -o $@ @echo 'Finished building: $(@F)' @echo ' ' -$(OBJ_FOLDER)%.o : %.cpp +$(OBJ_FOLDER)%.o : %.cpp | create_outputdir @echo 'Building file: $(@F)' @echo 'Invoking: MCU C++ Compiler' $(CXX) $(CXXFLAGS) $(COMMON_FLAGS) $< -o $@ @echo 'Finished building: $(@F)' @echo ' ' -$(OBJ_FOLDER)%.o : %.s +$(OBJ_FOLDER)%.o : %.s | create_outputdir @echo 'Building file: $(@F)' @echo 'Invoking: MCU Assembler' $(AS) $(ASFLAGS) $(COMMON_FLAGS) $< -o $@ @@ -131,14 +130,18 @@ $(OBJ_FOLDER)%.o : %.s PRE_BUILD_SCRIPT := $(shell{% for command in pre_build_script %} ../../../{{command}} && {% endfor %} true) -all: create_outputdir $(OBJ_FOLDER)$(TARGET)$(TARGET_EXT) print_info +all: $(OBJ_FOLDER)$(TARGET)$(TARGET_EXT) print_info {% for command in post_build_script %} ../../../{{command}} && {% endfor %} true create_outputdir: ifeq ($(OS),Windows_NT) - -mkdir $(OUT_DIR) + -@mkdir $(OUT_FOLDER) +{% for dir in source_paths %} + -@mkdir $(OBJ_FOLDER){{dir}}{% endfor %} else - $(shell mkdir $(OBJ_FOLDER) 2>/dev/null) + @mkdir -p $(OBJ_FOLDER) 2>/dev/null +{% for dir in source_paths %} + @mkdir -p $(OBJ_FOLDER){{dir}} 2>/dev/null{% endfor %} endif {% if output_type == 'exe' %} @@ -172,6 +175,9 @@ print_info: @echo ' ' {% endif %} +{% for rule in additional_targets %}{{rule}} +{% endfor %} + # Other Targets clean: @echo 'Removing entire out directory' diff --git a/project_generator/templates/makefile_armcc.tmpl b/project_generator/templates/makefile_armcc.tmpl index 8bbe5dd5..d2a42677 100644 --- a/project_generator/templates/makefile_armcc.tmpl +++ b/project_generator/templates/makefile_armcc.tmpl @@ -1,4 +1,4 @@ -{% extends "makefile.tmpl" %} + {% extends "makefile.tmpl" %} {% block CC %}armcc{% endblock %} {% block CXX %}armcc{% endblock %} @@ -12,5 +12,5 @@ {% block objcopy_output %}--output{% endblock %} {% block COMMON_FLAGS %} --cpu $(CPU) --$(INSTRUCTION_MODE){% endblock %} -{% block LD_OPTIONS %}--strict --scatter $(LD_SCRIPT) $(patsubst %,--predefine "%",$(CC_SYMBOLS) $(INC_DIRS_F)){% endblock %} +{% block LD_OPTIONS %}--strict --scatter $(filter %.sct, $^) $(patsubst %,--predefine "%",$(CC_SYMBOLS) $(INC_DIRS_F)){% endblock %} {% block ASM_SYMBOLS %}{% for symbol in macros %} --pd "{{ morph_define(symbol) }}" {% endfor %}{% endblock %} \ No newline at end of file diff --git a/project_generator/templates/makefile_gcc.tmpl b/project_generator/templates/makefile_gcc.tmpl index 0aaebe2e..a442026d 100644 --- a/project_generator/templates/makefile_gcc.tmpl +++ b/project_generator/templates/makefile_gcc.tmpl @@ -10,5 +10,5 @@ {% block TOBIN %}-O binary{% endblock %} {% block COMMON_FLAGS %} -mcpu=$(CPU) -m$(INSTRUCTION_MODE) -MMD -MP $(CC_SYMBOLS) {% endblock %} -{% block LD_OPTIONS %} -mcpu=$(CPU) -m$(INSTRUCTION_MODE) -Wl,-Map=$(OBJ_FOLDER)$(TARGET).map,--cref -T$(LD_SCRIPT){% endblock %} +{% block LD_OPTIONS %} -mcpu=$(CPU) -m$(INSTRUCTION_MODE) -Wl,-Map=$(OBJ_FOLDER)$(TARGET).map,--cref -T$(filter-out %.o, $^){% endblock %} {% block ASM_SYMBOLS %}$(CC_SYMBOLS){% endblock %} diff --git a/project_generator/tools/gccarm.py b/project_generator/tools/gccarm.py index 2373eb01..6f3534d4 100644 --- a/project_generator/tools/gccarm.py +++ b/project_generator/tools/gccarm.py @@ -12,44 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -import copy -import os +from copy import deepcopy import logging -import ntpath -import subprocess -from itertools import chain -from os.path import join, normpath,dirname -from project_generator_definitions.definitions import ProGenDef - -from .tool import Tool,Exporter -from ..util import SOURCE_KEYS +from .makefile import MakefileTool logger = logging.getLogger('progen.tools.gccarm') -class MakefileGccArm(Tool, Exporter): - - # http://www.gnu.org/software/make/manual/html_node/Running.html - ERRORLEVEL = { - 0: 'no errors)', - 1: 'targets not already up to date', - 2: 'errors' - } - - SUCCESSVALUE = 0 - - optimization_options = ['O0', 'O1', 'O2', 'O3', 'Os'] - - generated_projects = { - 'path': '', - 'files': { - 'makefile' : '', - } - } +class MakefileGccArm(MakefileTool): def __init__(self, workspace, env_settings): - self.workspace = workspace - self.env_settings = env_settings + MakefileTool.__init__(self, workspace, env_settings, logging) @staticmethod def get_toolnames(): @@ -59,102 +32,14 @@ def get_toolnames(): def get_toolchain(): return 'gcc_arm' - def _parse_specific_options(self, data): - """ Parse all specific setttings. """ - data['common_flags'] = [] - data['ld_flags'] = [] - data['c_flags'] = [] - data['cxx_flags'] = [] - data['asm_flags'] = [] - for k, v in data['misc'].items(): - if type(v) is list: - if k not in data: - data[k] = [] - data[k].extend(v) - else: - if k not in data: - data[k] = '' - data[k] = v - - def _get_libs(self, project_data): - project_data['lib_paths'] =[] - project_data['libraries'] =[] - for lib in project_data['source_files_lib']: - head, tail = ntpath.split(lib) - file = tail - if (os.path.splitext(file)[1] != ".a"): - logging.debug("Found %s lib with non-valid extension (!=.a)" % file) - continue - else: - file = file.replace(".a","") - project_data['lib_paths'].append(head) - project_data['libraries'].append(file.replace("lib",'')) - - def export_workspace(self): - logger.debug("Makefile GCC ARM currently does not support workspaces") - def export_project(self): """ Processes misc options specific for GCC ARM, and run generator """ - generated_projects = copy.deepcopy(self.generated_projects) + generated_projects = deepcopy(self.generated_projects) self.process_data_for_makefile(self.workspace) generated_projects['path'], generated_projects['files']['makefile'] = self.gen_file_jinja('makefile_gcc.tmpl', self.workspace, 'Makefile', self.workspace['output_dir']['path']) return generated_projects - def get_generated_project_files(self): - return {'path': self.workspace['path'], 'files': [self.workspace['files']['makefile']]} - def process_data_for_makefile(self, project_data): - #Flatten our dictionary, we don't need groups - for key in SOURCE_KEYS: - project_data[key] = list(chain(*project_data[key].values())) - self._get_libs(project_data) - self._parse_specific_options(project_data) - project_data['toolchain'] = 'arm-none-eabi-' project_data['toolchain_bin_path'] = self.env_settings.get_env_settings('gcc') - - pro_def = ProGenDef() - - if pro_def.get_mcu_core(project_data['target'].lower()): - project_data['core'] = pro_def.get_mcu_core(project_data['target'].lower())[0] - else: - raise RuntimeError( - "Target: %s not found, Please add the target to https://github.com/project-generator/project_generator_definitions" % project_data['target'].lower()) - - # gcc arm is funny about cortex-m4f. - if project_data['core'] == 'cortex-m4f': - project_data['core'] = 'cortex-m4' - - # change cortex-m0+ to cortex-m0plus - if project_data['core'] == 'cortex-m0+': - project_data['core'] = 'cortex-m0plus' - - def build_project(self): - # cwd: relpath(join(project_path, ("gcc_arm" + project))) - # > make all - path = dirname(self.workspace['files']['makefile']) - logger.debug("Building GCC ARM project: %s" % path) - - args = ['make', 'all'] - logger.debug(args) - - try: - ret_code = None - ret_code = subprocess.call(args, cwd=path) - except: - logger.error("Project: %s build error whilst calling make. Is it in your PATH?" % self.workspace['files']['makefile']) - return -1 - else: - if ret_code != self.SUCCESSVALUE: - # Seems like something went wrong. - if ret_code < 3: - logger.error("Project: %s build failed with the status: %s" % - (self.ERRORLEVEL[ret_code], self.workspace['files']['makefile'])) - else: - logger.error("Project: %s build failed with unknown error. Returned: %s" % - (ret_code, self.workspace['files']['makefile'])) - return -1 - else: - logger.info("Build succeeded with the status: %s" % - self.ERRORLEVEL[ret_code]) - return 0 + MakefileTool.process_data_for_makefile(self, project_data) diff --git a/project_generator/tools/makearmcc.py b/project_generator/tools/makearmcc.py index c8f2f6a1..3479dbf0 100644 --- a/project_generator/tools/makearmcc.py +++ b/project_generator/tools/makearmcc.py @@ -12,44 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -import copy -import os +from copy import deepcopy import logging -import ntpath -import subprocess -from itertools import chain -from os.path import join, normpath,dirname -from project_generator_definitions.definitions import ProGenDef - -from .tool import Tool,Exporter -from ..util import SOURCE_KEYS +from .makefile import MakefileTool logger = logging.getLogger('progen.tools.armcc') -class MakefileArmcc(Tool, Exporter): - - # http://www.gnu.org/software/make/manual/html_node/Running.html - ERRORLEVEL = { - 0: 'no errors)', - 1: 'targets not already up to date', - 2: 'errors' - } - - SUCCESSVALUE = 0 - - optimization_options = ['O0', 'O1', 'O2', 'O3', 'Os'] - - generated_projects = { - 'path': '', - 'files': { - 'makefile' : '', - } - } +class MakefileArmcc(MakefileTool): def __init__(self, workspace, env_settings): - self.workspace = workspace - self.env_settings = env_settings + MakefileTool.__init__(self, workspace, env_settings, logger) @staticmethod def get_toolnames(): @@ -59,101 +32,18 @@ def get_toolnames(): def get_toolchain(): return 'armcc' - def _parse_specific_options(self, data): - """ Parse all specific setttings. """ - data['common_flags'] = [] - data['ld_flags'] = [] - data['c_flags'] = [] - data['cxx_flags'] = [] - data['asm_flags'] = [] - data['pre_build_script'] = [] - data['post_build_script'] = [] - for k, v in data['misc'].items(): - if type(v) is list: - if k not in data: - data[k] = [] - data[k].extend(v) - else: - if k not in data: - data[k] = '' - data[k] = v - - def _get_libs(self, project_data): - project_data['lib_paths'] =[] - project_data['libraries'] =[] - for lib in project_data['source_files_lib']: - head, tail = ntpath.split(lib) - file = tail - if (os.path.splitext(file)[1] != ".a"): - logging.debug("Found %s lib with non-valid extension (!=.a)" % file) - continue - else: - file = file.replace(".a","") - project_data['lib_paths'].append(head) - project_data['libraries'].append(file.replace("lib",'')) - - def export_workspace(self): - logger.debug("Makefile ARMCC currently does not support workspaces") - def export_project(self): """ Processes misc options specific for GCC ARM, and run generator """ - generated_projects = copy.deepcopy(self.generated_projects) + generated_projects = deepcopy(self.generated_projects) self.process_data_for_makefile(self.workspace) generated_projects['path'], generated_projects['files']['makefile'] = self.gen_file_jinja('makefile_armcc.tmpl', self.workspace, 'Makefile', self.workspace['output_dir']['path']) return generated_projects - def get_generated_project_files(self): - return {'path': self.workspace['path'], 'files': [self.workspace['files']['makefile']]} - def process_data_for_makefile(self, project_data): - #Flatten our dictionary, we don't need groups - for key in SOURCE_KEYS: - project_data[key] = list(chain(*project_data[key].values())) - self._get_libs(project_data) - self._parse_specific_options(project_data) def morph_define (define) : if '=' in define : return define.replace("=", " SETA ") else : return define + " SETA 1 " - - project_data['toolchain'] = '' - project_data['preprocess_asm_seperately'] = True project_data['morph_define'] = morph_define - - pro_def = ProGenDef() - - - if pro_def.get_mcu_core(project_data['target'].lower()): - project_data['core'] = pro_def.get_mcu_core(project_data['target'].lower())[0] - else: - raise RuntimeError( - "Target: %s not found, Please add the target to https://github.com/project-generator/project_generator_definitions" % project_data['target'].lower()) - - def build_project(self): - path = dirname(self.workspace['files']['makefile']) - logger.debug("Building ARMCC project: %s" % path) - - args = ['make', 'all'] - logger.debug(args) - - try: - ret_code = None - ret_code = subprocess.call(args, cwd=path) - except: - logger.error("Project: %s build error whilst calling make. Is it in your PATH?" % self.workspace['files']['makefile']) - return -1 - else: - if ret_code != self.SUCCESSVALUE: - # Seems like something went wrong. - if ret_code < 3: - logger.error("Project: %s build failed with the status: %s" % - (self.ERRORLEVEL[ret_code], self.workspace['files']['makefile'])) - else: - logger.error("Project: %s build failed with unknown error. Returned: %s" % - (ret_code, self.workspace['files']['makefile'])) - return -1 - else: - logger.info("Build succeeded with the status: %s" % - self.ERRORLEVEL[ret_code]) - return 0 + MakefileTool.process_data_for_makefile(self, project_data) diff --git a/project_generator/tools/makefile.py b/project_generator/tools/makefile.py new file mode 100644 index 00000000..76804915 --- /dev/null +++ b/project_generator/tools/makefile.py @@ -0,0 +1,151 @@ +# Copyright 2014-2015 0xc0170, theotherjimmy +# +# 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 copy +import os +import logging +import ntpath +import subprocess +from itertools import chain + +from os.path import join, normpath,dirname +from project_generator_definitions.definitions import ProGenDef + +from .tool import Tool, Exporter +from ..util import SOURCE_KEYS, strip_start + + +class MakefileTool(Tool, Exporter): + + ERRORLEVEL = { + 0: 'no errors)', + 1: 'targets not already up to date', + 2: 'errors' + } + + SUCCESSVALUE = 0 + + optimization_options = ['O0', 'O1', 'O2', 'O3', 'Os'] + + generated_projects = { + 'path': '', + 'files': { + 'makefile' : '', + } + } + + def __init__(self, workspace, env_settings, logging): + self.workspace = workspace + self.env_settings = env_settings + self.logging = logging + + + def _parse_specific_options(self, data): + """ Parse all specific setttings. """ + data['common_flags'] = [] + data['ld_flags'] = [] + data['c_flags'] = [] + data['cxx_flags'] = [] + data['asm_flags'] = [] + for k, v in data['misc'].items(): + if type(v) is list: + if k not in data: + data[k] = [] + data[k].extend(v) + else: + if k not in data: + data[k] = '' + data[k] = v + + def _get_libs(self, project_data): + project_data['lib_paths'] =[] + project_data['libraries'] =[] + for lib in project_data['source_files_lib']: + head, tail = ntpath.split(lib) + file = tail + if (os.path.splitext(file)[1] != ".a"): + self.logging.debug("Found %s lib with non-valid extension (!=.a)" % file) + continue + else: + file = file.replace(".a","") + project_data['lib_paths'].append(head) + project_data['libraries'].append(file.replace("lib",'')) + + def export_workspace(self): + self.logging.debug("Makefiles currently do not support workspaces") + + def get_generated_project_files(self): + return {'path': self.workspace['path'], 'files': [self.workspace['files']['makefile']]} + + def process_data_for_makefile(self, project_data): + #Flatten our dictionary, we don't need groups + for key in SOURCE_KEYS: + project_data[key] = list(chain(*project_data[key].values())) + self._get_libs(project_data) + self._parse_specific_options(project_data) + + + pro_def = ProGenDef() + + if pro_def.get_mcu_core(project_data['target'].lower()): + project_data['core'] = pro_def.get_mcu_core(project_data['target'].lower())[0] + else: + raise RuntimeError( + "Target: %s not found, Please add the target to https://github.com/project-generator/project_generator_definitions" % project_data['target'].lower()) + + # gcc arm is funny about cortex-m4f. + if project_data['core'] == 'cortex-m4f': + project_data['core'] = 'cortex-m4' + + # change cortex-m0+ to cortex-m0plus + if project_data['core'] == 'cortex-m0+': + project_data['core'] = 'cortex-m0plus' + + for key in ['source_files_c','source_files_cpp','source_files_s', 'source_paths']: + project_data[key] = [strip_start(f,project_data['output_dir']['rel_path']) + for f in project_data[key]] + project_data['linker_file'] = strip_start(project_data['linker_file'], + project_data['output_dir']['rel_path']) + + def build_project(self): + # cwd: relpath(join(project_path, ("gcc_arm" + project))) + # > make all + path = dirname(self.workspace['files']['makefile']) + self.logging.debug("Building GCC ARM project: %s" % path) + + args = ['make', 'all'] + self.logging.debug(args) + + try: + ret_code = None + ret_code = subprocess.call(args, cwd=path) + except: + self.logging.error("Project: %s build error whilst calling make. Is it in your PATH?" % self.workspace['files']['makefile']) + return -1 + else: + if ret_code != self.SUCCESSVALUE: + # Seems like something went wrong. + if ret_code < 3: + self.logging.error("Project: %s build failed with the status: %s" % + (self.ERRORLEVEL[ret_code], self.workspace['files']['makefile'])) + else: + self.logging.error("Project: %s build failed with unknown error. Returned: %s" % + (ret_code, self.workspace['files']['makefile'])) + return -1 + else: + + + self.logging.info("Build succeeded with the status: %s" % + self.ERRORLEVEL[ret_code]) + return 0 diff --git a/project_generator/util.py b/project_generator/util.py index 6156b008..87176ffe 100644 --- a/project_generator/util.py +++ b/project_generator/util.py @@ -88,6 +88,13 @@ def get_field(self, field_name, args, kwargs): val = '{' + field_name + '}', first return val +def strip_start(text, prefix): + if text == [] : + return [] + if not text.startswith(prefix): + return text + return text[len(prefix):] + def fix_paths(project_data, rel_path, extensions): """ Fix paths for extension list """ norm_func = lambda path : os.path.normpath(os.path.join(rel_path, path))