Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 80 additions & 55 deletions CubeMX2Makefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
mcu_cflags[re.compile('STM32(F|L)4')] = '-mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp'
mcu_cflags[re.compile('STM32(F|L)7')] = '-mthumb -mcpu=cortex-m7 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp'

if len(sys.argv) != 2:
sys.stderr.write("\r\nSTM32CubeMX project to Makefile V1.5\r\n")
sys.stderr.write("-==================================-\r\n")
sys.stderr.write("Written by Baoshi <mail\x40ba0sh1.com> on 2015-10-03\r\n")
sys.stderr.write("Copyright www.ba0sh1.com\r\n")
sys.stderr.write("Apache License 2.0 <http://www.apache.org/licenses/LICENSE-2.0>\r\n")
sys.stderr.write("Updated for STM32CubeMX Version 4.10.1 http://www.st.com/stm32cube\r\n")
sys.stderr.write("Usage:\r\n")
sys.stderr.write(" CubeMX2Makefile.py <STM32CubeMX \"Toolchain Folder Location\">\r\n")
if len(sys.argv) != 3:
sys.stderr.write("\nSTM32CubeMX project to Makefile V1.5\n")
sys.stderr.write("-==================================-\n")
sys.stderr.write("Written by Baoshi <mail\x40ba0sh1.com> on 2015-10-03\n")
sys.stderr.write("Copyright www.ba0sh1.com\n")
sys.stderr.write("Apache License 2.0 <http://www.apache.org/licenses/LICENSE-2.0>\n")
sys.stderr.write("Updated for STM32CubeMX Version 4.10.1 http://www.st.com/stm32cube\n")
sys.stderr.write("Usage:\n")
sys.stderr.write(" CubeMX2Makefile.py <STM32CubeMX \"Toolchain Folder Location\"> \"<STM32CubeMX Repository location>\"\n")
sys.exit(C2M_ERR_INVALID_COMMANDLINE)

# Load template files
Expand All @@ -43,52 +43,69 @@
mft = Template(fd.read())
fd.close()
except:
sys.stderr.write("Unable to load template file CubeMX2Makefile.tpl\r\n")
sys.stderr.write("Unable to load template file CubeMX2Makefile.tpl\n")
sys.exit(C2M_ERR_LOAD_TEMPLATE)

proj_folder = os.path.abspath(sys.argv[1])
if not os.path.isdir(proj_folder):
sys.stderr.write("STM32CubeMX \"Toolchain Folder Location\" %s not found\r\n" % proj_folder)
sys.stderr.write("STM32CubeMX \"Toolchain Folder Location\" \"%s\" is not found\n" % proj_folder)
sys.exit(C2M_ERR_INVALID_COMMANDLINE)

reposytory_folder = os.path.abspath(sys.argv[2])
if not os.path.isdir(reposytory_folder):
sys.stderr.write("STM32CubeMX \"Reposytory location\" \"%s\" is not found\n" % proj_folder)
sys.exit(C2M_ERR_INVALID_COMMANDLINE)

proj_name = os.path.splitext(os.path.basename(proj_folder))[0]
ac6_project = proj_folder + os.path.sep + 'SW4STM32' + os.path.sep + proj_name + ' Configuration' + os.path.sep + '.project'
ac6_cproject = proj_folder + os.path.sep + 'SW4STM32' + os.path.sep + proj_name + ' Configuration' + os.path.sep + '.cproject'
for root, dirs, files in os.walk(proj_folder + os.path.sep + "SW4STM32"):
for file in files:
if file == ".project":
ac6_project = root + os.path.sep + file
elif file== ".cproject":
ac6_cproject = root + os.path.sep + file

if not (os.path.isfile(ac6_project) and os.path.isfile(ac6_cproject)):
sys.stderr.write("SW4STM32 project not found, use STM32CubeMX to generate a SW4STM32 project first\r\n")
sys.stderr.write("SW4STM32 project not found, use STM32CubeMX to generate a SW4STM32 project first\n")
sys.exit(C2M_ERR_NO_PROJECT)


# .project file
try:
tree = ET.parse(ac6_project)
root = tree.getroot()
except Exception, e:
sys.stderr.write("Error: cannot parse SW4STM32 .project file: %s\r\n" % ac6_project)
sys.stderr.write("Error: cannot parse SW4STM32 .project file: %s\n" % ac6_project)
sys.exit(C2M_ERR_PROJECT_FILE)
nodes = root.findall('linkedResources/link[type=\'1\']/location')
nodes = root.findall('linkedResources/link')
sources = []
for node in nodes:
sources.append(re.sub(r'^PARENT-2-PROJECT_LOC/', '', node.text))
location = node.find('location').text
src_path = re.sub(r'^PARENT-[0-9]-PROJECT_LOC/(Drivers/.*|Middlewares/.*|Src/.*)', "$(PRJ_PATH)/\\1" , location)
if src_path != location:
sources.append(src_path)

sources=list(set(sources))
sources.sort()
c_sources = 'C_SOURCES ='
asm_sources = 'ASM_SOURCES ='
c_sources = ' \\\n'
asm_sources = ' \\\n'
for source in sources:
ext = os.path.splitext(source)[1]
if ext == '.c':
c_sources += ' \\\n ' + source
c_sources += " " + source + " \\\n"
elif ext == '.s':
asm_sources = asm_sources + ' \\\n ' + source
asm_sources += " " + source + " \\\n"
else:
sys.stderr.write("Unknow source file type: %s\r\n" % source)
sys.stderr.write("Unknow source file type: %s\n" % source)
sys.exit(-5)
asm_sources = asm_sources[:-2] + "\n"
c_sources = c_sources[:-2] + "\n"

# .cproject file
try:
tree = ET.parse(ac6_cproject)
root = tree.getroot()
except Exception, e:
sys.stderr.write("Error: cannot parse SW4STM32 .cproject file: %s\r\n" % ac6_cproject)
sys.stderr.write("Error: cannot parse SW4STM32 .cproject file: %s\n" % ac6_cproject)
sys.exit(C2M_ERR_PROJECT_FILE)
# MCU
mcu = ''
Expand All @@ -97,7 +114,7 @@
try:
value = node.attrib.get('value')
except Exception, e:
sys.stderr.write("No target MCU defined\r\n")
sys.stderr.write("No target MCU defined\n")
sys.exit(C2M_ERR_PROJECT_FILE)
for pattern, option in mcu_cflags.items():
if pattern.match(value):
Expand All @@ -107,79 +124,87 @@
if ('m7' in ld_mcu):
ld_mcu = mcu_cflags[re.compile('STM32(F|L)4')]
if (mcu == '' or ld_mcu == ''):
sys.stderr.write("Unknown MCU\r\n, please contact author for an update of this utility\r\n")
sys.stderr.write("Unknown MCU\n, please contact author for an update of this utility\n")
sys.stderr.exit(C2M_ERR_NEED_UPDATE)
# AS include
as_includes = 'AS_INCLUDES ='
# ASM include
asm_includes = '\\\n'
nodes = root.findall('.//tool[@superClass="fr.ac6.managedbuild.tool.gnu.cross.assembler"]/option[@valueType="includePath"]/listOptionValue')
first = 1
for node in nodes:
value = node.attrib.get('value')
if (value != ""):
value = re.sub(r'^..(\\|/)..(\\|/)..(\\|/)', '', value.replace('\\', os.path.sep))
if first:
as_includes = 'AS_INCLUDES = -I' + value
first = 0
else:
as_includes += '\nAS_INCLUDES += -I' + value
value = re.sub(r'((\.\.\/)*\.\./|^/)Inc$', "$(PRJ_PATH)/Inc", value)
value = re.sub(r'((\.\.\/)*\.\./)Drivers\/', "$(PRJ_PATH)/Drivers/", value)
value = re.sub(r'((\.\.\/)*\.\./)Middlewares\/', "$(PRJ_PATH)/Middlewares/", value)
value = re.sub(r'((\.\.\/)*\.\./|^/root/.*/)Drivers\/', "$(REPO_PATH)/Drivers/", value)
value = re.sub(r'((\.\.\/)*\.\./|^/root/.*/)Middlewares\/', "$(REPO_PATH)/Middlewares/", value)
asm_includes += " -I" + value + " \\\n"
asm_includes = asm_includes[:-2] + "\n"

# AS symbols
as_defs = 'AS_DEFS ='
asm_defs = '\\\n'
# C include
c_includes = 'C_INCLUDES ='
c_includes = "\\\n"
nodes = root.findall('.//tool[@superClass="fr.ac6.managedbuild.tool.gnu.cross.c.compiler"]/option[@valueType="includePath"]/listOptionValue')
first = 1
for node in nodes:
value = node.attrib.get('value')
if (value != ""):
value = re.sub(r'^..(\\|/)..(\\|/)..(\\|/)', '', value.replace('\\', os.path.sep))
if first:
c_includes = 'C_INCLUDES = -I' + value
first = 0
else:
c_includes += '\nC_INCLUDES += -I' + value
value = re.sub(r'((\.\.\/)*\.\./|^/)Inc$', "$(PRJ_PATH)/Inc", value)
value = re.sub(r'((\.\.\/)*\.\./)Drivers\/', "$(PRJ_PATH)/Drivers/", value)
value = re.sub(r'((\.\.\/)*\.\./)Middlewares\/', "$(PRJ_PATH)/Middlewares/", value)
value = re.sub(r'((\.\.\/)*\.\./|^/root/.*/)Drivers\/', "$(REPO_PATH)/Drivers/", value)
value = re.sub(r'((\.\.\/)*\.\./|^/root/.*/)Middlewares\/', "$(REPO_PATH)/Middlewares/", value)
c_includes += " -I" + value + " \\\n"
c_includes = c_includes[:-2] + "\n"

# C symbols
c_defs = 'C_DEFS ='
c_defs = '\\\n'
nodes = root.findall('.//tool[@superClass="fr.ac6.managedbuild.tool.gnu.cross.c.compiler"]/option[@valueType="definedSymbols"]/listOptionValue')
for node in nodes:
value = node.attrib.get('value')
if (value != ""):
c_defs += ' -D' + re.sub(r'([()])', r'\\\1', value)
c_defs += ' -D' + re.sub(r'([()])', r'\\\1', value) + " \\\n"
c_defs = c_defs[:-2] + "\n"

# Link script
ldscript = 'LDSCRIPT = '
ldscript = ''
node = root.find('.//tool[@superClass="fr.ac6.managedbuild.tool.gnu.cross.c.linker"]/option[@superClass="fr.ac6.managedbuild.tool.gnu.cross.c.linker.script"]')
try:
value = node.attrib.get('value')
value = re.sub(r'^..(\\|/)..(\\|/)..(\\|/)', '', value.replace('\\', os.path.sep))
value = os.path.basename(value)
except Exception, e:
sys.stderr.write("No link script defined\r\n")
sys.exit(C2M_ERR_PROJECT_FILE)
sys.stderr.write("No link script defined\n")
sys.exit(C2M_ERR_PROJECT_FILE)
# copy link script to top level so that user can discard SW4STM32 folder
src = proj_folder + os.path.sep + 'SW4STM32' + os.path.sep + proj_name + ' Configuration' + os.path.sep + value
src = os.path.dirname(ac6_cproject) + os.path.sep + value
dst = proj_folder + os.path.sep + value

shutil.copyfile(src, dst)
sys.stdout.write("File created: %s\r\n" % dst)
ldscript += value
sys.stdout.write("File created: %s\n" % dst)
ldscript += value

mf = mft.substitute( \
TARGET = proj_name, \
PRJ_PATH = proj_folder, \
REPO_PATH = reposytory_folder, \
MCU = mcu, \
LDMCU = ld_mcu, \
C_SOURCES = c_sources, \
ASM_SOURCES = asm_sources, \
AS_DEFS = as_defs, \
AS_INCLUDES = as_includes, \
ASM_DEFS = asm_defs, \
ASM_INCLUDES = asm_includes, \
C_DEFS = c_defs, \
C_INCLUDES = c_includes, \
LDSCRIPT = ldscript)
try:
fd = open(proj_folder + os.path.sep + 'Makefile', 'wb')
fd.write(mf)
fd.write("\n")
fd.close()
except:
sys.stderr.write("Write Makefile failed\r\n")
sys.stderr.write("Write Makefile failed\n")
sys.exit(C2M_ERR_IO)
sys.stdout.write("File created: %s\r\n" % (proj_folder + os.path.sep + 'Makefile'))
sys.stdout.write("File created: %s\n" % (proj_folder + os.path.sep + 'Makefile'))

sys.exit(C2M_ERR_SUCCESS)

38 changes: 31 additions & 7 deletions CubeMX2Makefile.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ OPT = -O0
# source path
# Build path
BUILD_DIR = build
PRJ_PATH = $PRJ_PATH
REPO_PATH = $REPO_PATH

######################################
# source
######################################
$C_SOURCES
$ASM_SOURCES
C_SOURCES = $C_SOURCES
ASM_SOURCES = $ASM_SOURCES

#######################################
# binaries
Expand All @@ -43,11 +45,11 @@ BIN = $$(CP) -O binary -S
# CFLAGS
#######################################
# macros for gcc
$AS_DEFS
$C_DEFS
ASM_DEFS = $ASM_DEFS
C_DEFS = $C_DEFS
# includes for gcc
$AS_INCLUDES
$C_INCLUDES
ASM_INCLUDES = $ASM_INCLUDES
C_INCLUDES = $C_INCLUDES
# compile gcc flags
ASFLAGS = $MCU $$(AS_DEFS) $$(AS_INCLUDES) $$(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS = $MCU $$(C_DEFS) $$(C_INCLUDES) $$(OPT) -Wall -fdata-sections -ffunction-sections
Expand All @@ -61,7 +63,7 @@ CFLAGS += -MD -MP -MF .dep/$$(@F).d
# LDFLAGS
#######################################
# link script
$LDSCRIPT
LDSCRIPT = $LDSCRIPT
# libraries
LIBS = -lc -lm -lnosys
LIBDIR =
Expand All @@ -70,6 +72,28 @@ LDFLAGS = $LDMCU -specs=nano.specs -T$$(LDSCRIPT) $$(LIBDIR) $$(LIBS) -Wl,-Map=$
# default action: build all
all: $$(BUILD_DIR)/$$(TARGET).elf $$(BUILD_DIR)/$$(TARGET).hex $$(BUILD_DIR)/$$(TARGET).bin

#######################################################
# Printing variables needed for generating any project
#######################################################
C_DEFS_PRINT:
@echo $$(C_DEFS)

C_SOURCES_PRINT:
@echo $$(C_SOURCES)

C_INCLUDES_PRINT:
@echo $$(C_INCLUDES)

ASM_SOURCES_PRINT:
@echo $$(ASM_SOURCES)

ASM_DEFS_PRINT:
@echo $$(ASM_DEFS)

ASM_INCLUDES_PRINT:
@echo $$(ASM_INCLUDES)
#######################################################

#######################################
# build the application
#######################################
Expand Down