idle wrote:I've made a tool to do exports for linux but I haven't done it for windows
sent you a pm with the linux code
Thanks for the code, idle. I followed a different approach and tried to create a custom PB IDE tool.
I came up with the following Python (2.7.x) code:
Code: Select all
import os.path
import sys
import re
PB_INCLUDE_PATH = re.compile(r'IncludePath "(.+)"')
PB_INCLUDE_FILE = re.compile(r'IncludeFile "(.+)"')
PB_XINCLUDE_FILE = re.compile(r'XIncludeFile "(.+)"')
PB_PROCEDURE = re.compile(r'Procedure(\.\w)? (\w+)\(')
PB_PROCEDUREC = re.compile(r'ProcedureC(\.\w)? (\w+)\(')
PB_PROCEDURE_DLL = re.compile(r'ProcedureDLL(\.\w)? (\w+)\(')
PB_PROCEDUREC_DLL = re.compile(r'ProcedureCDLL(\.\w)? (\w+)\(')
PB_PROCEDURE_CALL = re.compile(r'(\w+)\(')
PB_PROTOTYPE = re.compile(r'Prototype(\.\w)? (\w+)\(')
PB_MACRO = re.compile(r'Macro (\w+)\(')
def is_called(procedure, procedure_calls, checked):
if not procedure in procedure_calls:
return False
parents = procedure_calls[procedure]
if None in parents:
parents = [None]
return True
if procedure in checked:
return False
checked.append(procedure)
for parent in parents:
if is_called(parent, procedure_calls, checked):
parents = [None]
return True
return False
def process(path, compilefile, include=None, includes=[], procedures={}, procedure_calls={}):
lines = []
lline = 0
with open(include or compilefile, 'r') as file:
lines = file.readlines()
procedure = None
importing = False
if include:
include_path = os.path.dirname(include)
else:
include_path = path
for lnum, line in enumerate(lines):
line = line.strip()
if line.startswith(';'):
if 'IDE Options' in line:
lline = lnum
continue
pb_include_path = PB_INCLUDE_PATH.match(line)
if pb_include_path:
include_path = os.path.join(path, pb_include_path.group(1).strip())
pb_include_file = PB_INCLUDE_FILE.match(line)
if pb_include_file:
include_file = os.path.join(include_path, pb_include_file.group(1).strip())
process(path, compilefile, include_file, includes, procedures, procedure_calls)
pb_xinclude_file = PB_XINCLUDE_FILE.match(line)
if pb_xinclude_file:
xinclude_file = os.path.join(include_path, pb_xinclude_file.group(1).strip())
if not xinclude_file in includes:
includes.append(xinclude_file)
process(path, compilefile, xinclude_file, includes, procedures, procedure_calls)
pb_procedure = PB_PROCEDURE.match(line)
if pb_procedure:
procedure = pb_procedure.group(2).strip()
procedures[procedure] = {'name': procedure, 'number': len(procedures)*2, 'type': ''}
continue
pb_procedure = PB_PROCEDUREC.match(line)
if pb_procedure:
procedure = pb_procedurec.group(2).strip()
procedures[procedure] = {'name': procedure, 'number': len(procedures)*2, 'type': 'C'}
continue
pb_procedure = PB_PROCEDURE_DLL.match(line)
if pb_procedure:
procedure = pb_procedure.group(2).strip()
procedures[procedure] = {'name': procedure, 'number': len(procedures)*2, 'type': ''}
continue
pb_procedure = PB_PROCEDUREC_DLL.match(line)
if pb_procedure:
procedure = pb_procedurec.group(2).strip()
procedures[procedure] = {'name': procedure, 'number': len(procedures)*2, 'type': 'C'}
continue
pb_prototype = PB_PROTOTYPE.match(line)
if pb_prototype:
procedure = pb_prototype.group(2).strip()
procedures[procedure] = {'name': procedure, 'number': len(procedures)*2}
continue
pb_macro = PB_MACRO.match(line)
if pb_macro:
procedure = pb_macro.group(1).strip()
continue
if 'EndProcedure' in line:
procedure = None
continue
if 'Procedure' in line:
continue
if 'EndMacro' in line:
procedure = None
continue
if 'Macro' in line:
continue
if 'EndImport' in line:
importing = False
continue
if 'Import' in line:
importing = True
continue
pb_procedure_calls = PB_PROCEDURE_CALL.finditer(line)
for pb_procedure_call in pb_procedure_calls:
procedure_call = pb_procedure_call.group(1).strip()
if importing:
procedures[procedure_call] = {'name': procedure_call, 'number': len(procedures)*2}
else:
if procedure_call in procedure_calls:
procedure_calls[procedure_call].append(procedure)
else:
procedure_calls[procedure_call] = [procedure]
if not include:
if procedures:
procedures = procedures.values()
procedures = filter(lambda procedure: 'type' in procedure, procedures)
procedures = sorted(procedures, key=lambda procedure: procedure['number'], reverse=True)
for procedure in procedures:
lines.insert(lline, ';> _Procedure%(number)d = %(name)s\n' % procedure)
procedures = filter(lambda procedure: is_called(procedure['name'], procedure_calls, []), procedures)
if procedures:
lines.insert(lline, '!SYS_EndDataSection:}\n')
for procedure in procedures:
lines.insert(lline, ' !public _Procedure%(number)d as \'%(name)s\'\n' % procedure)
lines.insert(lline, '!macro SYS_EndDataSection name{\n')
for procedure in procedures:
lines.insert(lline, 'Import%(type)s "/EXPORT:%(name)s" : EndImport\n' % procedure)
with open(compilefile, 'w') as file:
file.writelines(lines)
def main(argv):
if len(argv) >= 3:
process(argv[1], argv[2])
if __name__ == '__main__':
main(sys.argv)
Configure it like shown in the following screenshot:
Unfortunately there seems to be a limit on the number of exports pbcompiler can handle.
I tried to find those limits per PureBasic edition using the following code:
Code: Select all
import subprocess
import time
TEMPLATE = '''
ProcedureDLL Test%(num)d()
MessageRequester("Test", "Hello World!", #PB_MessageRequester_Ok)
EndProcedure
Import "/EXPORT:Test%(num)d"
EndImport
!public _Procedure%(num)d As 'Test%(num)d'
'''
if __name__ == '__main__':
x86 = None
x64 = None
for max in range(50, 200, 2):
print max
with open('gentest.pb', 'w+') as file:
for num in range(0, max*2, 2):
file.write(TEMPLATE % {'num': num})
if not x86:
try:
subprocess.check_output([r'C:\Program Files (x86)\PureBasic\Compilers\pbcompiler.exe', '/EXE', 'gentest_x86.exe', 'gentest.pb'])
time.sleep(0.2)
except:
x86 = max
if not x64:
try:
subprocess.check_output([r'C:\Program Files\PureBasic\Compilers\pbcompiler.exe', '/EXE', 'gentest_x64.exe', 'gentest.pb'])
time.sleep(0.2)
except:
x64 = max
if x86 and x64:
break
print 'PureBasic x86 max =', x86
print 'PureBasic x64 max =', x64
This is the result on my machine:
Code: Select all
PureBasic x86 max = 92
PureBasic x64 max = 194