2017-02-11 158 views
1

我目前正在尝试使用SDCC OS compilerSTM8 microcontroller开发C库和项目模板。我的目标是一个类似于Arduino的(几乎)NOOB兼容设置 - 但是使用make + shellscripts而不是IDE(对我的野心有限制)...具有依赖关系的Arduino-like Makefile ...?

目前我正在努力使自动检测依赖关系。在Arduino中,用户只包括相关的标题,例如“#include LCD-lib”,构建机制自动检测依赖关系并链接各自的库。无需手动将其添加到IDE或Makefile。

我喜欢这种简单,但到目前为止,我在创建相应的Makefile时失败惨重。基本上这里是Makefile应该实现的:

  1. 扫描项目根目录中的* .c文件以获取包含的标题。请注意,这些文件都位于不同的lib文件夹
  2. 相应的C-添加文件都包含标题和(如果存在)的构建过程
  3. ,以尽量减少编译时间和大小,未使用的C文件在lib文件夹必须构建

我有信心,使能做到期间,将跳过所有上面 - 而不是在我的水平与经验,化妆... :-(

这里的文件夹结构,我想到:

├── Library 
│   ├── Base 
│   │   ├── general STM8 sources and headers 
│   ├── STM8S_Discovery 
│   │   └── board specific sources and headers 
│   └── User 
│      └── optional user library sources and headers 
├── Projects 
│   ├── Examples (to be filled) 
│   │   └── Basic_Project 
│   │    ├── compile_upload.sh --> double-click to build and upload 
│   │    ├── config.h 
│   │    ├── main.c 
│   │    └── Makefile   --> should detect dependencies in ./*.c and ./*.h 
│   └── User_Projects (still empty) 
└── Tools 
    ├── programmer.py    --> for programming (already works from make) 
    └── terminal.py    --> for serial terminal (already works from make) 

我知道要问很多,但一个方便的Makefile是我的主要障碍。任何帮助非常感谢!提前感谢!

问候, 乔治·伊京,Konert

+0

您是否考虑过下载另一个IDE(例如,像Simplicity Studio这样的基于Eclipse的IDE),构建一个简单的项目,并说明IDE如何生成Makefiles?这将是一个很好的起点。 –

+0

请注意,在Arduino环境中,用户界面和/或库生成的额外代码预先写入每个编译单元中的用户'.ino'代码。你也可以使用Makefiles来做到这一点,为处理增加一个额外的步骤。 (一种方法是使用预处理器将预处理后的源文件创建到构建目录中,并为每个编译单元提供单独的部分。)这里需要做的是手工完成整个构建过程(以及写下来),包括不同的选项处理;然后,将其用作编写Makefile的概要。 –

回答

0

注:我意识到这个答案并不符合您的所有要求,事实上,这种方法仍然要求您列出您在项目中使用的相关Arduino库的名称,以及路径列表到应该包含在项目中的目录。但是,这个解决方案与我的想法最为接近,它可能仍然帮助其他人阅读这个问题。


我用的Arduino的Makefile此:

  1. Makefile文件。掌握在主工作区目录
  2. 当你开始一个新的的Arduino项目,创建它作为一个子目录在您的工作空间
    • 创建一个单独的文件包含setup()和'环.pde/.ino扩展()方法
    • 把剩下的逻辑为.c/.cpp/.h/.hpp文件
  3. 添加项目的Makefile日使用make allmake uploadmake monitor

确保您有picocom安装

# Your Arduino environment. 
ARD_HOME = /usr/share/arduino 
ARD_BIN = $(ARD_HOME)/hardware/tools/avr/bin 

# Monitor Baudrate 
MON_SPEED = 4800 

# Board settings. 
BOARD = uno 
PORT = /dev/ttyACM0 
PROGRAMMER = stk500v2 

# Where to find header files and libraries. 
INC_DIRS = 
MY_LIB_DIRS = 
LIBS = 
LIB_DIRS = $(addprefix $(ARD_HOME)/libraries/, $(LIBS)) $(MY_LIB_DIRS) 

include ../Makefile.master 
  • 编译和运行:在套项目精制这个子目录中的设置,例如您的Unix/Linux机器(或相当于)控制台串行监视器。在MAC-OS上,您可以使用屏幕通过相应地设置MON_CMD变量。


    Makefile.master:

    原始Makefile.master写由Alan BurlisonMatthieu Weber修改,并且可以发现here

    我做了一些改动,使其适合我的配置,尤其是我已经添加几行代码:

    ### DEBUG Compilation ### 
    ifeq ($(DEBUG), 1) 
        ARD_FLAGS += -DDEBUG_PROJ 
        C_FLAGS += -g 
        CXX_FLAGS += -g 
    else 
        ARD_FLAGS += -DNDEBUG_PROJ 
    endif 
    

    ,并随后被移除从默认C/CXX _FLAGS-g选项Makefile.master。以这种方式符号信息不添加上释放码,只有当代码与DEBUG=1编译由

    #ifdef DEBUG_PROJ 
        /* debug code here */ 
    #endif 
    // or 
    #ifndef NDEBUG_PROJ 
        /* debug code here */ 
    #endif 
    

    找到其成二进制屏蔽的代码,从而导致更小的释放可执行文件。

    在这里你可以找到我自己的版本的Makefile。主

    # 
    # Copyright 2011 Alan Burlison, [email protected] All rights reserved. 
    # Subsequently modified by Matthieu Weber, [email protected] 
    # Subsequently modified by Patrick Trentin, [email protected] 
    # Use is subject to license terms. 
    # 
    # Redistribution and use in source and binary forms, with or without 
    # modification, are permitted provided that the following conditions are met: 
    # 
    # 1. Redistributions of source code must retain the above copyright notice, 
    #  this list of conditions and the following disclaimer. 
    # 
    # 2. Redistributions in binary form must reproduce the above copyright notice, 
    #  this list of conditions and the following disclaimer in the documentation 
    #  and/or other materials provided with the distribution. 
    # 
    # THIS SOFTWARE IS PROVIDED BY ALAN BURLISON "AS IS" AND ANY EXPRESS OR IMPLIED 
    # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
    # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
    # EVENT SHALL ALAN BURLISON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
    # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
    # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
    # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
    # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
    # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
    # 
    # Makefile for building Arduino projects outside of the Arduino environment 
    # 
    # This makefile should be included into a per-project Makefile of the following 
    # form: 
    # 
    # ---------- 
    # BOARD = mega 
    # PORT = /dev/term/0 
    # INC_DIRS = ../common 
    # LIB_DIRS = ../libraries/Task ../../libraries/VirtualWire 
    # include ../../Makefile.master 
    # ---------- 
    # 
    # Where: 
    # BOARD : Arduino board type, from $(ARD_HOME)/hardware/boards.txt 
    # PORT  : USB port 
    # INC_DIRS : List pf directories containing header files 
    # LIB_DIRS : List of directories containing library source 
    # 
    # Before using this Makefile you can adjust the following macros to suit 
    # your environment, either by editing this file directly or by defining them in 
    # the Makefile that includes this one, in which case they will override the 
    # definitions below: 
    # ARD_REV  : arduino software revision, e.g. 0017, 0018 
    # ARD_HOME  : installation directory of the Arduino software. 
    # ARD_BIN  : location of compiler binaries 
    # AVRDUDE  : location of avrdude executable 
    # AVRDUDE_CONF : location of avrdude configuration file 
    # PROGRAMMER : avrdude programmer type 
    # MON_TERM  : terminal command for serial monitor 
    # MON_CMD  : serial monitor command 
    # MON_SPEED : serial monitor speed 
    # 
    
    # Global configuration. 
    ARD_REV ?= 100 
    ARD_HOME ?= /usr/local/arduino 
    ARD_BIN ?= /usr/bin 
    AVRDUDE ?= $(ARD_HOME)/hardware/tools/avrdude 
    AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avrdude.conf 
    MON_TERM ?= xterm 
    MON_SPEED ?= 57600 
    MON_CMD ?= picocom 
    PORT ?= $(HOME)/dev/arduino 
    BOARD ?= atmega328 
    
    ### Nothing below here should require editing. ### 
    
    # Check for the required definitions. 
    
    ifndef BOARD 
        $(error $$(BOARD) not defined) 
    endif 
    ifndef PORT 
        $(error $$(PORT) not defined) 
    endif 
    
    # Version-specific settings 
    ARD_BOARDS = $(ARD_HOME)/hardware/arduino/boards.txt 
    ARD_SRC_DIR = $(ARD_HOME)/hardware/arduino/cores/arduino 
    ARD_MAIN = $(ARD_SRC_DIR)/main.cpp 
    
    # Standard macros. 
    SKETCH = $(notdir $(CURDIR)) 
    BUILD_DIR = build 
    VPATH = $(LIB_DIRS) 
    
    # Macros derived from boards.txt 
    MCU := $(shell sed -n 's/$(BOARD)\.build\.mcu=\(.*\)/\1/p' < $(ARD_BOARDS)) 
    F_CPU := $(shell sed -n 's/$(BOARD)\.build\.f_cpu=\(.*\)/\1/p' < $(ARD_BOARDS)) 
    UPLOAD_SPEED := \ 
        $(shell sed -n 's/$(BOARD)\.upload\.speed=\(.*\)/\1/p' < $(ARD_BOARDS)) 
    PROGRAMMER := \ 
        $(shell sed -n 's/$(BOARD)\.upload\.protocol=\(.*\)/\1/p' < $(ARD_BOARDS)) 
    ARD_VAR := \ 
        $(shell sed -n 's/$(BOARD)\.build\.variant=\(.*\)/\1/p' < $(ARD_BOARDS)) 
    
    # More Version-specific settings 
    ARD_VAR_DIR = $(ARD_HOME)/hardware/arduino/variants/$(ARD_VAR) 
    
    # Build tools. 
    CC = $(ARD_BIN)/avr-gcc 
    CXX = $(ARD_BIN)/avr-g++ 
    CXXFILT = $(ARD_BIN)/avr-c++filt 
    OBJCOPY = $(ARD_BIN)/avr-objcopy 
    OBJDUMP = $(ARD_BIN)/avr-objdump 
    AR = $(ARD_BIN)/avr-ar 
    SIZE = $(ARD_BIN)/avr-size 
    NM = $(ARD_BIN)/avr-nm 
    MKDIR = mkdir -p 
    RM = rm -rf 
    MV = mv -f 
    LN = ln -f 
    
    # Compiler flags. 
    INC_FLAGS = \ 
        $(addprefix -I,$(INC_DIRS)) $(addprefix -I,$(LIB_DIRS)) -I$(ARD_SRC_DIR) -I$(ARD_VAR_DIR) 
    ARD_FLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -DARDUINO=$(ARD_REV) 
    C_CXX_FLAGS = \ 
        -Wall -Wextra -Wundef -Wno-unused-parameter \ 
        -fdiagnostics-show-option -Wa,-adhlns=$(BUILD_DIR)/$*.lst 
    C_FLAGS = \ 
        $(C_CXX_FLAGS) -std=gnu99 -Wstrict-prototypes -Wno-old-style-declaration 
    CXX_FLAGS = $(C_CXX_FLAGS) 
    
    ### DEBUG Compilation ### 
    ifeq ($(DEBUG), 1) 
        ARD_FLAGS += -DDEBUG_PROJ 
        C_FLAGS += -g 
        CXX_FLAGS += -g 
    else 
        ARD_FLAGS += -DNDEBUG_PROJ 
    endif 
    
    # Optimiser flags. 
    #  optimise for size, unsigned by default, pack data. 
    #  separate sections, drop unused ones, shorten branches, jumps. 
    #  don't inline, vectorise loops. no exceptions. 
    #  no os preamble, use function calls in prologues. 
    # http://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/ 
    # http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html 
    OPT_FLAGS = \ 
        -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \ 
        -ffunction-sections -fdata-sections -Wl,--gc-sections,--relax \ 
        -fno-inline-small-functions -fno-tree-scev-cprop -fno-exceptions \ 
        -ffreestanding -mcall-prologues 
    
    # Build parameters. 
    IMAGE = $(BUILD_DIR)/$(SKETCH) 
    ARD_C_SRC = $(wildcard $(ARD_SRC_DIR)/*.c) 
    ARD_CXX_SRC = $(wildcard $(ARD_SRC_DIR)/*.cpp) 
    ARD_C_OBJ = $(patsubst %.c,%.o,$(notdir $(ARD_C_SRC))) 
    ARD_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(ARD_CXX_SRC))) 
    ARD_LIB = arduino 
    ARD_AR = $(BUILD_DIR)/lib$(ARD_LIB).a 
    ARD_AR_OBJ = $(ARD_AR)($(ARD_C_OBJ) $(ARD_CXX_OBJ)) 
    ARD_LD_FLAG = -l$(ARD_LIB) 
    
    # Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734 
    $(ARD_AR)(Tone.o) : CXX_FLAGS += -w 
    
    # Sketch libraries. 
    LIB_C_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.c)) 
    LIB_CXX_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.cpp)) 
    LIB_SRC = $(LIB_C_SRC) $(LIB_CXX_SRC) 
    ifneq "$(strip $(LIB_C_SRC) $(LIB_CXX_SRC))" "" 
        LIB_C_OBJ = $(patsubst %.c,%.o,$(notdir $(LIB_C_SRC))) 
        LIB_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(LIB_CXX_SRC))) 
        LIB_LIB = library 
        LIB_AR = $(BUILD_DIR)/lib$(LIB_LIB).a 
        LIB_AR_OBJ = $(LIB_AR)($(LIB_C_OBJ) $(LIB_CXX_OBJ)) 
        LIB_LD_FLAG = -l$(LIB_LIB) 
    endif 
    
    # Sketch PDE source. 
    SKT_PDE_SRC = $(wildcard *.pde *.ino) 
    ifneq "$(strip $(SKT_PDE_SRC))" "" 
        SKT_PDE_OBJ = $(BUILD_DIR)/$(SKETCH)_pde.o 
    endif 
    
    # C and C++ source. 
    SKT_C_SRC = $(wildcard *.c) 
    SKT_CXX_SRC = $(wildcard *.cpp) 
    ifneq "$(strip $(SKT_C_SRC) $(SKT_CXX_SRC))" "" 
        SKT_C_OBJ = $(patsubst %.c,%.o,$(SKT_C_SRC)) 
        SKT_CXX_OBJ = $(patsubst %.cpp,%.o,$(SKT_CXX_SRC)) 
        SKT_LIB = sketch 
        SKT_AR = $(BUILD_DIR)/lib$(SKT_LIB).a 
        SKT_AR_OBJ = $(SKT_AR)/($(SKT_C_OBJ) $(SKT_CXX_OBJ)) 
        SKT_LD_FLAG = -l$(SKT_LIB) 
    endif 
    
    # Definitions. 
    define run-cc 
        @ $(CC) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '[email protected]($%)' -MF [email protected]_$*.dep $< 
        $(CC) -c $(C_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \ 
         $< -o $(BUILD_DIR)/$% 
        @ $(AR) rc [email protected] $(BUILD_DIR)/$% 
        @ $(RM) $(BUILD_DIR)/$% 
        @ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp 
        @ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst 
    endef 
    
    define run-cxx 
        @ $(CXX) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '[email protected]($%)' -MF [email protected]_$*.dep $< 
        $(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \ 
         $< -o $(BUILD_DIR)/$% 
        @ $(AR) rc [email protected] $(BUILD_DIR)/$% 
        @ $(RM) $(BUILD_DIR)/$% 
        @ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp 
        @ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst 
    endef 
    
    # Rules. 
    .PHONY : all clean upload monitor upload_monitor 
    
    all : $(BUILD_DIR) $(IMAGE).hex 
    
    clean : 
        $(RM) $(BUILD_DIR) 
    
    $(BUILD_DIR) : 
        $(MKDIR) [email protected] 
    
    $(SKT_PDE_OBJ) : $(SKT_PDE_SRC) 
        if [ $(ARD_REV) -ge 100 ]; then \ 
        echo '#include "Arduino.h"' > $(BUILD_DIR)/$(SKETCH)_pde.cpp; \ 
        else \ 
        echo '#include "WProgram.h"' > $(BUILD_DIR)/$(SKETCH)_pde.cpp; \ 
        fi 
        echo '#include "$(SKT_PDE_SRC)"' >> $(BUILD_DIR)/$(SKETCH)_pde.cpp 
        $(LN) $(SKT_PDE_SRC) $(BUILD_DIR)/$(SKT_PDE_SRC) 
        cd $(BUILD_DIR) && $(CXX) -c $(subst build/,,$(CXX_FLAGS)) \ 
         $(OPT_FLAGS) $(ARD_FLAGS) -I.. \ 
         $(patsubst -I..%,-I../..%,$(INC_FLAGS)) \ 
         $(SKETCH)_pde.cpp -o $(@F) 
    
    (%.o) : $(ARD_SRC_DIR)/%.c 
        $(run-cc) 
    
    (%.o) : $(ARD_SRC_DIR)/%.cpp 
        $(run-cxx) 
    
    (%.o) : %.c 
        $(run-cc) 
    
    (%.o) : %.cpp 
        $(run-cxx) 
    
    $(BUILD_DIR)/%.d : %.c 
        $(run-cc-d) 
    
    $(BUILD_DIR)/%.d : %.cpp 
        $(run-cxx-d) 
    
    $(IMAGE).hex : $(ARD_AR_OBJ) $(LIB_AR_OBJ) $(SKT_AR_OBJ) $(SKT_PDE_OBJ) 
        $(CC) $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) -L$(BUILD_DIR) \ 
         $(SKT_PDE_OBJ) $(SKT_LD_FLAG) $(LIB_LD_FLAG) $(ARD_LD_FLAG) -lm \ 
         -o $(IMAGE).elf 
        $(OBJCOPY) -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load \ 
         --no-change-warnings --change-section-lma .eeprom=0 $(IMAGE).elf \ 
         $(IMAGE).eep 
        $(OBJCOPY) -O ihex -R .eeprom $(IMAGE).elf $(IMAGE).hex 
        $(OBJDUMP) -h -S $(IMAGE).elf | $(CXXFILT) -t > $(IMAGE).lst 
        $(SIZE) $(IMAGE).hex 
    
    upload : all 
        - pkill -f '$(MON_CMD).*$(PORT)' 
        - sleep 1 
        - stty -F $(PORT) hupcl 
        - $(AVRDUDE) -V -C$(AVRDUDE_CONF) -p$(MCU) -c$(PROGRAMMER) -P$(PORT) \ 
         -b$(UPLOAD_SPEED) -D -Uflash:w:$(IMAGE).hex:i 
    
    monitor : 
        LD_LIBRARY_PATH= LD_PRELOAD= \ 
         $(MON_TERM) -title '$(BOARD) $(PORT)' \ 
         -e '$(MON_CMD) -b $(MON_SPEED) $(PORT)' & 
    
    upload_monitor : upload monitor 
    
    -include $(wildcard $(BUILD_DIR)/*.dep)) 
    # vim:ft=make 
    

    使用示例:

    给出一个目录树喜欢如下:

    Base_Dir 
    ├── Library 
    │   ├── Base 
    │   │   ├── general STM8 sources and headers 
    │   ├── STM8S_Discovery 
    │   │   └── board specific sources and headers 
    │   └── User 
    │      └── optional user library sources and headers 
    ├── Projects 
    │   ├── Examples (to be filled) 
    │   │   └── Basic_Project 
    │   │    ├── config.h 
    │   │    ├── example.ino 
    │   │    └── Makefile   --> should detect dependencies in ./*.c and ./*.h 
    ... 
    

    你可以把内ProjectsMakefile.master,然后假设:

    • 你只需要的是在Library/BaseLibrary/User这个项目
    • 您需要使用LiquidCrystal Arduino的库项目

    ,那么你会添加以下MakefileBasic Project

    # Your Arduino environment. 
    BASE_DIR = /path/to/Base_Dir    # to edit 
    ARD_HOME = /usr/share/arduino    # to edit, maybe 
    ARD_BIN = $(ARD_HOME)/hardware/tools/avr/bin 
    
    # Monitor Baudrate 
    MON_SPEED = 4800 
    
    # Board settings. 
    BOARD = uno 
    PORT = /dev/ttyACM0 
    PROGRAMMER = stk500v2 
    
    # Where to find header files and libraries. 
    INC_DIRS = 
    MY_LIB_DIRS= $(BASE_DIR)/Library/Base $(BASE_DIR)/Library/User 
    LIBS= LiquidCrystal 
    LIB_DIRS = $(addprefix $(ARD_HOME)/libraries/, $(LIBS)) $(MY_LIB_DIRS) 
    
    include ../../Makefile.master 
    

    注意common.h应该会自动检测贝科使用它位于.,并且不应该将后者添加到INC_DIRS


    最后请注意:最后我测试了这个配置,我使用的版本1.0.5的Arduino源代码,这是完美的工作时间。

  • 0

    你可以找到一个讨论,以实现样品一起,为GNU自动依存产生方法使here。你不会说你在使用GNU make,所以我只是假设。

    我不知道这对你是否足够;从你关于你的要求的陈述中不清楚。

    +0

    感谢您的快速响应,我会看看。 是的,我使用的是GNU make。对不起,不提。 我会告诉你,如果这符合我的需求 - 和理解水平... – user7549304

    0

    首先感谢很多都为快速和大力支持!我问过要早得多......

    现在回到我的(不再是)问题。我现在明白了,我居然问2个不同的问题:

    • 依赖于头 - >双方帕特里克或MadScientist的建议
    • 检测是由例如需要什么样的图书馆解决在调用分析main.c中 main.o,或由#包括 ...?

    我明白第二个难度更大,从内部实现......!?但Patrick的Makefile使得手动配置非常方便。所以没关系我:-)

    [添加timeslip ...]好了,说完思索更多一些,将下面的工作/有意义吗?

    1. 呼叫例如从内部的Makefile徒劳无功或Python脚本所有执行#included头隔离来自的* .c的* .h在项目目录
    2. 每个包括XYZ。^ h检查是否相应make_xyz在lib目录下存在,(将是库的一部分)
    3. 如果是,包括生成文件编译在主的Makefile

    这是否在某种程度上合理...?再次感谢,祝你有美好的一天,无论你身在何处!

    此致,Georg Icking-Konert

    +0

    这个空间是保留*答案*,实际上解决你的问题,你应该按你的问题上的* [edit] *按钮添加更多信息而不是创建答案。话虽如此,是的,这是一个可行的方法,如果你碰巧实现点** 1。**发布代码在这里将是一个很好的答案你自己的问题。 :) –

    +0

    嗨帕特里克, 感谢您的意见。作为一个新手,我不知道这个规则。希望这一个现在是正确的; ;-) – user7549304

    +0

    嗨再次, 好吧,我会尝试实现上述1.作为python脚本,因为我也使用python的串行终端。希望它不会太长。 我是否应该通过具有标准名称的文件传递所需* make_xyz *的列表,该文件是静态包含在master-Makefile中的? – user7549304

    0

    再次感谢您的支持!

    遵循上述建议,我编写了一个小型python脚本,它使用gcc(或实际上是sdcc)依赖关系生成器。下面的脚本扫描所有项目.c文件为#included使用gcc的头文件。然后在项目和库文件夹中搜索相应的头文件。如果存在相应的.c文件(与标题相同的路径和名称),则将其添加到Makefile中。重复此过程,直到找不到新的标题。

    结果是一个Makefile,它只生成模块#include模块在项目.c文件中 - 就像在Arduino IDE中一样。它可能不够高雅,但是这个工作:-)

    脚本中的95-106行是编译器和项目特定的,必须相应地进行修改。玩得开心,再次感谢!

    #!/usr/bin/python 
    
    ''' 
    automatically create a Makefile with dependencies from 
    all .c files in a starting directory 
    ''' 
    
    # required modules 
    import sys 
    import os 
    import platform 
    import shlex 
    from subprocess import Popen, PIPE 
    
    # set OS specific 
    OS = platform.system() 
    if OS == 'Windows': 
        MAKE  = 'mingw32-make.exe' 
    else: 
        MAKE  = 'make' 
    
    
    ################## 
    # helper functions 
    ################## 
    
    ######### 
    def getchar(): 
        """ 
        python equivalent of getchar() 
        """ 
        ch = 0 
        if OS == 'Windows': 
        import msvcrt as m 
        ch = m.getch() 
        sys.stdio.flush() 
        sys.stderr.flush() 
        else: 
        import sys, tty, termios 
        fd = sys.stdin.fileno() 
        old_settings = termios.tcgetattr(fd) 
        tty.setraw(sys.stdin.fileno()) 
        ch = sys.stdin.read(1) 
        return ch 
        # end getchar() 
    
    
    ######### 
    def listFiles(start='.', pattern='.c'): 
        """ 
        return set of matching files in project folder incl. subfolders 
        """ 
        result = set() 
        for root, dirs, files in os.walk(start): 
        for file in files: 
         if file.endswith(pattern): 
         #print(os.path.join(root, file)) 
         result.add(os.path.join(root, file)) 
        return result 
        # end listFiles() 
    
    
    ######### 
    def listSubdirs(start='.'): 
        """ 
        return set of subdirectories in given folder 
        """ 
        result = set() 
        for root, dirs, files in os.walk(start): 
        for dir in dirs: 
         #print(os.path.join(root, dir)) 
         result.add(os.path.join(root, dir)) 
        return result 
        # end listFiles() 
    
    
    ######### 
    def get_exitcode_stdout_stderr(cmd): 
        """ 
        execute the external command and get its exitcode, stdout and stderr. 
        """ 
        args = shlex.split(cmd) 
        proc = Popen(args, stdout=PIPE, stderr=PIPE) 
        out, err = proc.communicate() 
        exitcode = proc.returncode 
        return exitcode, out, err 
    
    
    
    ################## 
    # main program 
    ################## 
    
    # set compile search paths 
    ROOT_DIR = '../../../' 
    TOOL_DIR = ROOT_DIR + 'Tools/' 
    LIB_ROOT = ROOT_DIR + 'Library/' 
    PRJ_ROOT = '.' 
    OBJDIR = 'output' 
    TARGET = 'main.ihx' 
    
    # set command for creating dependencies and set search paths 
    CC  = 'sdcc ' 
    CFLAGS = '-mstm8 --std-sdcc99 --std-c99 ' 
    LFLAGS = '-mstm8 -lstm8 --out-fmt-ihx ' 
    DEPEND = '-MM ' 
    INCLUDE = '-I. ' 
    for dir in listSubdirs(PRJ_ROOT): 
        INCLUDE += '-I' + dir + ' ' 
    for dir in listSubdirs(LIB_ROOT): 
        INCLUDE += '-I' + dir + ' ' 
    
    # get set of .c files in project folder incl. subdirectories 
    source_todo = listFiles(PRJ_ROOT,".c") 
    source_done = set() 
    header_done = set() 
    object_done = set() 
    
    
    # print message 
    sys.stdout.write('start Makefile creation ... ') 
    sys.stdout.flush() 
    
    
    # generate generic Makefile header 
    Makefile = open('Makefile', 'wb') 
    Makefile.write('OBJDIR = '+OBJDIR+'\n') 
    Makefile.write('TARGET = '+TARGET+'\n\n') 
    Makefile.write('.PHONY: clean all default objects\n\n') 
    Makefile.write('.PRECIOUS: $(TARGET)\n\n') 
    Makefile.write('default: $(OBJDIR) $(OBJDIR)/$(TARGET)\n\n') 
    Makefile.write('all: default\n\n') 
    Makefile.write('# create output folder\n') 
    Makefile.write('$(OBJDIR):\n') 
    Makefile.write(' mkdir -p $(OBJDIR)\n') 
    Makefile.write(' rm -fr -- -p\n\n') 
    
    # iteratively add project sources to Makefile 
    while (len(source_todo) > 0): 
    
        # get next pending source and mark as done 
        source = source_todo.pop() 
        source_done.add(source) 
    
        # convert Windows path to POSIX for Makefile 
        if OS == 'Windows': 
        source = source.replace('\\','/') 
    
        # use compiler generate dependency list 
        cmd = CC+DEPEND+CFLAGS+INCLUDE+source 
        #print cmd 
        exitcode, out, err = get_exitcode_stdout_stderr(cmd) 
        if (exitcode != 0): 
        print 'error: ' + err 
        getchar() 
        exit() 
    
        # append .c file with dependency and compile instruction to Makefile 
        Makefile.write('$(OBJDIR)/'+out) 
        #print(out) 
        Makefile.write('\t'+CC+CFLAGS+INCLUDE+'-c $< -o [email protected]\n\n') 
    
        # extract file list including object[0], source[1] and headers[2..N] 
        out = out.replace(':', '') 
        out = out.replace('\\', '') 
        out = out.replace('\n', '') 
        out = out.split() 
        #print out 
    
        # for all files returned by compiler... 
        for next in out: 
    
        # append object files for linker 
        if next.endswith('.rel'): 
         object_done.add(next) 
    
        # if corresponding source to header exists, add to pending sources 
        if next.endswith('.h'): 
         if next not in header_done:   # not yet in list 
         header_done.add(next)     # add to treated headers 
         if (os.path.isfile(next[:-1]+'c')): # if corresponding .c exists, add to todo list 
          source_todo.add(next[:-1]+'c') 
    
    
    # link project object files 
    Makefile.write('$(OBJDIR)/$(TARGET): ') 
    for next in object_done: 
        Makefile.write('$(OBJDIR)/'+next+' ') 
    Makefile.write('\n') 
    Makefile.write('\t'+CC+LFLAGS) 
    for next in object_done: 
        Makefile.write('$(OBJDIR)/'+next+' ') 
    Makefile.write(' -o [email protected]\n') 
    
    # close Makefile.dep 
    Makefile.close() 
    
    
    print('done\n') 
    sys.stdout.write('press any key to exit') 
    getchar() 
    exit() 
    
    # END OF MODULE