Skip to content

Instantly share code, notes, and snippets.

@Sh-ui
Last active March 31, 2019 17:13
Show Gist options
  • Save Sh-ui/40b65a9c6ff4ae2216e9c2d369b5e6d7 to your computer and use it in GitHub Desktop.
Save Sh-ui/40b65a9c6ff4ae2216e9c2d369b5e6d7 to your computer and use it in GitHub Desktop.
small tool to compile python to an exec file
from collections import OrderedDict, namedtuple
def dicto(ref, name='dictionary_object'):
ref = ref.copy() # copy the original dictionary to edit a copy
keys = []
vals = []
for k, v in ref.items():
k = ''.join(c for c in k if c.isalpha()) # remove non alphanumeric characters
keys += [k] # append keys from ref to list of new keys
vals += [v] # append values from ref to list of new values
dct = OrderedDict(zip(keys, vals)) # zip both lists into one ordered dictionary
dct_obj = namedtuple(name, dct.keys())(*dct.values()) # make each item a class attribute
return dct_obj # return the object created from the dictionary
"""
(PYCX) PYthon to Cython to eXec, a unix command line util
Usage:
pycx FILES... [-o DIR --verbose --delete --run]
pycx --help
Options:
FILES one or more python files to compile
-o --output=DIR output directory
-v --verbose show output while exec compiles
-d --delete delete the c file after compiling exec
-r --run run the exec after compiling
-h --help show this screen
"""
from os import system as shell
from pathlib import Path
from docopt import docopt, DocoptExit
from dicto import dicto # makes arguments callable as class attributes, without the "--"
# the two pathnames below tell gcc where python is so that cython can be compiled to an exec
INCLUDE = '/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/include/python3.7m'
LIBRARY = '/usr/local/Cellar/python/3.7.2_2/Frameworks/Python.framework/Versions/3.7/lib'
CONCISE = '&>/dev/null' # tag this onto the end of shell commands to hide their output
def main(arg):
for file in arg.FILES:
path = Path(file)
if path.suffix not in ('.py', '.pyx'):
raise DocoptExit('add at least one python file\n') # show usage section of doc
c_file = path.parent / (path.stem + '.c')
output = Path(arg.output or '') / path.stem # just a file name if no argument
shell(f'cython --embed -o {c_file} {path}') # compile python to cython C file
shell(
f'gcc -v -Os -I {INCLUDE} -L {LIBRARY} {c_file} ' # compile C file to exec
f'-o {output} -lpython3.7 -lpthread -lm -lutil -ldl '
+ CONCISE if not arg.verbose else '' # hide gcc output if no argument
)
if arg.delete:
shell(f'find {path.parent} -name "{path.stem}.c" -type f|xargs rm -f')
if arg.run:
shell(f'./{output}')
if __name__ == '__main__':
main(dicto(docopt(__doc__)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment