'''
Visual studio project file generator
Grbl_ESP32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl_ESP32. If not, see .
@authors: atlaste [github.com/atlaste]
'''
PATHS_TO_SEARCH = ['Grbl_Esp32']
HEADER_EXT = ['.h', '.inl']
SOURCE_EXT = ['.c', '.cpp']
OTHER_EXT = ['.ino', '.md']
import os, uuid
def UUID(name):
return str(uuid.uuid3(uuid.NAMESPACE_OID, name)).upper()
def FilterFromPath(path):
(head, tail) = os.path.split(path)
head = head.replace('/', '\\').replace('..\\', '').replace('.\\', '')
if head == '.':
return ''
h = head[0:10];
if h == 'Grbl_Esp32':
h = head[11:]
return h
class Vcxproj:
# configuration, platform
ConfigurationFmt = '\n'.join([
' ',
' {0}',
' {1}',
' '])
# item name, item file
ItemFmt = '\n'.join([
' <{0} Include="{1}" />'])
# configuration, platform
ConfigTypePropertyGroupFmt = '\n'.join([
' ',
' Makefile',
' true',
' v142',
' '])
# configuration, platform
ImportGroupFmt = '\n'.join([
' ',
' ',
' '
])
# configuration, platform
PIOPropertyGroupFmt = '\n'.join([
' ',
' platformio --force run',
' platformio --force run -t clean',
' WIN32;_DEBUG;$(NMakePreprocessorDefinitions)',
' $(HOMEDRIVE)$(HOMEPATH)\\.platformio\\packages\\toolchain-xtensa32\\xtensa-esp32-elf\\include;$(HOMEDRIVE)$(HOMEPATH)\\.platformio\\packages\\framework-arduinoespressif32\\cores\\esp32;$(NMakeIncludeSearchPath)',
' '
])
@staticmethod
def Configuration(configuration, platform):
return Vcxproj.ConfigurationFmt.format(configuration, platform)
@staticmethod
def Item(name, file):
return Vcxproj.ItemFmt.format(name, file)
@staticmethod
def ConfigTypePropertyGroup(configuration, platform):
return Vcxproj.ConfigTypePropertyGroupFmt.format(configuration, platform)
@staticmethod
def ImportGroup(configuration, platform):
return Vcxproj.ImportGroupFmt.format(configuration, platform)
@staticmethod
def PIOPropertyGroup(configuration, platform):
return Vcxproj.PIOPropertyGroupFmt.format(configuration, platform)
class Filters:
# itemtype, path, folder
ItemFmt = '\n'.join([
' <{0} Include="{1}">',
' {2}',
' {0}>'])
# folder, uuid
FilterFmt = '\n'.join([
' ',
' {{{1}}}',
' '])
@staticmethod
def Item(itemtype, path):
folder = FilterFromPath(path)
return Filters.ItemFmt.format(itemtype, path, folder)
@staticmethod
def Filter(folder):
uid = UUID(folder)
return Filters.FilterFmt.format(folder, uid)
class Generator:
Folders = set()
# Files
Headers = set()
Sources = set()
Others = set()
# Stuffs
Platforms = set(['Win32','x64'])
Configurations = set(['Debug','Release'])
Name = 'Grbl_Esp32'
def AddFolder(self, path):
filt = FilterFromPath(path)
if filt == '':
return
if filt not in self.Folders:
self.Folders.add(filt)
filters = ''
for f in os.path.split(filt):
filters = os.path.join(filters, f)
if filters != '':
self.Folders.add(filters)
def AddFile(self, path):
(root, ext) = os.path.splitext(path)
if ext in HEADER_EXT:
self.Headers.add(path)
elif ext in SOURCE_EXT:
self.Sources.add(path)
elif ext in OTHER_EXT:
self.Others.add(path)
else:
return
self.AddFolder(path)
def Walk(self, path):
if path == 'Grbl_Esp32\\Custom' or path == 'Grbl_Esp32/Custom':
return
if os.path.isfile(path):
self.AddFile(path)
else:
for subPath in os.listdir(path):
self.Walk(os.path.join(path, subPath))
def CreateProject(self):
project = []
project.append('')
project.append('')
project.append('')
for p in self.Platforms:
for c in self.Configurations:
project.append(Vcxproj.Configuration(c, p))
project.append('')
# cpp header files
project.append('')
for f in self.Headers:
project.append(Vcxproj.Item('ClInclude', f))
project.append('')
# cpp source files
project.append('')
for f in self.Sources:
project.append(Vcxproj.Item('ClCompile', f))
project.append('')
# md files and ino file
project.append('')
for f in self.Others:
project.append(Vcxproj.Item('None', f))
project.append('')
# Bookkeeping, compilation, etc.
project.append('')
project.append(' 16.0')
project.append(' {11C8A44F-A303-4885-B5AD-5B65F7FE41C0}')
project.append(' Win32Proj')
project.append('')
project.append('')
for p in self.Platforms:
for c in self.Configurations:
project.append(Vcxproj.ConfigTypePropertyGroup(c, p))
project.append('')
project.append('')
project.append('')
project.append(' ')
project.append('')
for p in self.Platforms:
for c in self.Configurations:
project.append(Vcxproj.ImportGroup(c, p))
project.append('')
for p in self.Platforms:
for c in self.Configurations:
project.append(Vcxproj.PIOPropertyGroup(c, p))
project.append('')
project.append('')
project.append('')
project.append(' ')
project.append('')
project.append('')
project.append(' ')
project.append(' ')
project.append(' ')
project.append(' ')
project.append('')
return '\n'.join(project)
def CreateFilters(self):
project = []
project.append('')
project.append('')
project.append('')
for f in self.Folders:
project.append(Filters.Filter(f))
project.append('')
project.append('')
for f in self.Headers:
project.append(Filters.Item('ClInclude', f))
project.append('')
project.append('')
for f in self.Sources:
project.append(Filters.Item('ClCompile', f))
project.append('')
project.append('')
for f in self.Others:
project.append(Filters.Item('None', f))
project.append('')
project.append('')
return '\n'.join(project)
def Generate(self):
f = open(self.Name + '.vcxproj', 'w')
f.write(self.CreateProject())
f.close()
f = open(self.Name + '.vcxproj.filters', 'w')
f.write(self.CreateFilters())
f.close()
def main(paths):
generator = Generator()
for path in paths:
generator.Walk(path)
generator.Generate()
main(PATHS_TO_SEARCH)