Пример #1
0
def GenerateExe(name, targetKind, platform, machine, main_module):
    """generates the stub .EXE file for starting the app"""
    aName = AssemblyName(System.IO.FileInfo(name).Name)
    ab = PythonOps.DefineDynamicAssembly(aName,
                                         AssemblyBuilderAccess.RunAndSave)
    mb = ab.DefineDynamicModule(name, aName.Name + '.exe')
    tb = mb.DefineType('PythonMain', TypeAttributes.Public)
    mainMethod = tb.DefineMethod(
        'Main', MethodAttributes.Public | MethodAttributes.Static, int, ())
    if targetKind == System.Reflection.Emit.PEFileKinds.WindowApplication:
        mainMethod.SetCustomAttribute(
            clr.GetClrType(System.STAThreadAttribute).GetConstructor(()),
            System.Array[System.Byte](()))
    gen = mainMethod.GetILGenerator()

    # get the ScriptCode assembly...
    gen.EmitCall(OpCodes.Call,
                 clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
    gen.EmitCall(OpCodes.Call,
                 clr.GetClrType(Assembly).GetMethod("get_CodeBase"), ())
    gen.Emit(OpCodes.Newobj,
             clr.GetClrType(System.Uri).GetConstructor((str, )))
    gen.EmitCall(OpCodes.Call,
                 clr.GetClrType(System.Uri).GetMethod("get_LocalPath"), ())
    gen.Emit(OpCodes.Newobj,
             clr.GetClrType(System.IO.FileInfo).GetConstructor((str, )))
    gen.EmitCall(OpCodes.Call,
                 clr.GetClrType(System.IO.FileInfo).GetMethod("get_Directory"),
                 ())
    gen.EmitCall(
        OpCodes.Call,
        clr.GetClrType(System.IO.DirectoryInfo).GetMethod("get_FullName"), ())
    gen.EmitCall(
        OpCodes.Call,
        clr.GetClrType(System.Environment).GetMethod("set_CurrentDirectory"),
        ())
    gen.Emit(OpCodes.Ldstr, name + ".dll")
    gen.EmitCall(
        OpCodes.Call,
        clr.GetClrType(System.IO.Path).GetMethod("GetFullPath",
                                                 (clr.GetClrType(str), )), ())
    gen.EmitCall(
        OpCodes.Call,
        clr.GetClrType(System.Reflection.Assembly).GetMethod(
            "LoadFile", (clr.GetClrType(str), )), ())

    # emit module name
    gen.Emit(OpCodes.Ldstr, "__main__")

    gen.Emit(OpCodes.Ldnull)

    # call InitializeModule
    gen.EmitCall(OpCodes.Call,
                 clr.GetClrType(PythonOps).GetMethod("InitializeModule"), ())
    gen.Emit(OpCodes.Ret)

    tb.CreateType()
    ab.SetEntryPoint(mainMethod, targetKind)
    ab.Save(aName.Name + '.exe', platform, machine)
Пример #2
0
def GenerateExe(config):
    """generates the stub .EXE file for starting the app"""
    aName = AssemblyName(System.IO.FileInfo(config.output).Name)
    if config.file_version is not None:
        aName.Version = Version(config.file_version)
    
    ab = PythonOps.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave)
    ab.DefineVersionInfoResource(config.file_info_product, config.file_info_product_version, config.file_info_company, config.file_info_company, config.file_info_trademark)
    mb = ab.DefineDynamicModule(config.output,  aName.Name + ".exe")
    tb = mb.DefineType("PythonMain", TypeAttributes.Public)
    assemblyResolveMethod = None

    if config.standalone:
        print "Generating stand alone executable"
        config.embed = True
        
        for a in System.AppDomain.CurrentDomain.GetAssemblies():
            n = AssemblyName(a.FullName)
            if not a.IsDynamic and not a.EntryPoint and (n.Name.StartsWith("IronPython") or n.Name in ['Microsoft.Dynamic', 'Microsoft.Scripting']):                
                print "\tEmbedding %s %s" % (n.Name, str(n.Version))
                f = System.IO.FileStream(a.Location, System.IO.FileMode.Open, System.IO.FileAccess.Read)
                mb.DefineManifestResource("Dll." + n.Name, f, ResourceAttributes.Public)

        # we currently do no error checking on what is passed in to the assemblyresolve event handler
        assemblyResolveMethod = tb.DefineMethod("AssemblyResolve", MethodAttributes.Public | MethodAttributes.Static, clr.GetClrType(Assembly), (clr.GetClrType(System.Object), clr.GetClrType(System.ResolveEventArgs)))
        gen = assemblyResolveMethod.GetILGenerator()
        s = gen.DeclareLocal(clr.GetClrType(System.IO.Stream)) # resource stream
        gen.Emit(OpCodes.Ldnull)
        gen.Emit(OpCodes.Stloc, s)
        d = gen.DeclareLocal(clr.GetClrType(System.Array[System.Byte])) # data buffer
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
        gen.Emit(OpCodes.Ldstr, "Dll.")
        gen.Emit(OpCodes.Ldarg_1)    # The event args
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.ResolveEventArgs).GetMethod("get_Name"), ())
        gen.Emit(OpCodes.Newobj, clr.GetClrType(AssemblyName).GetConstructor((str, )))
        gen.EmitCall(OpCodes.Call, clr.GetClrType(AssemblyName).GetMethod("get_Name"), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(str).GetMethod("Concat", (str, str)), ())
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(Assembly).GetMethod("GetManifestResourceStream", (str, )), ())
        gen.Emit(OpCodes.Stloc, s)
        gen.Emit(OpCodes.Ldloc, s)
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.IO.Stream).GetMethod("get_Length"), ())
        gen.Emit(OpCodes.Newarr, clr.GetClrType(System.Byte))
        gen.Emit(OpCodes.Stloc, d)
        gen.Emit(OpCodes.Ldloc, s)
        gen.Emit(OpCodes.Ldloc, d)
        gen.Emit(OpCodes.Ldc_I4_0)
        gen.Emit(OpCodes.Ldloc, s)
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.IO.Stream).GetMethod("get_Length"), ())
        gen.Emit(OpCodes.Conv_I4)
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.IO.Stream).GetMethod("Read", (clr.GetClrType(System.Array[System.Byte]), int, int)), ())
        gen.Emit(OpCodes.Pop)
        gen.Emit(OpCodes.Ldloc, d)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("Load", (clr.GetClrType(System.Array[System.Byte]), )), ())
        gen.Emit(OpCodes.Ret)

        # generate a static constructor to assign the AssemblyResolve handler (otherwise it tries to use IronPython before it adds the handler)
        # the other way of handling this would be to move the call to InitializeModule into a separate method.
        staticConstructor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, System.Type.EmptyTypes)
        gen = staticConstructor.GetILGenerator()
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.AppDomain).GetMethod("get_CurrentDomain"), ())
        gen.Emit(OpCodes.Ldnull)
        gen.Emit(OpCodes.Ldftn, assemblyResolveMethod)
        gen.Emit(OpCodes.Newobj, clr.GetClrType(System.ResolveEventHandler).GetConstructor((clr.GetClrType(System.Object), clr.GetClrType(System.IntPtr))))
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.AppDomain).GetMethod("add_AssemblyResolve"), ())
        gen.Emit(OpCodes.Ret)        

    mainMethod = tb.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, int, ())
    if config.target == System.Reflection.Emit.PEFileKinds.WindowApplication and config.mta:
        mainMethod.SetCustomAttribute(clr.GetClrType(System.MTAThreadAttribute).GetConstructor(()), System.Array[System.Byte](()))
    elif config.target == System.Reflection.Emit.PEFileKinds.WindowApplication:
        mainMethod.SetCustomAttribute(clr.GetClrType(System.STAThreadAttribute).GetConstructor(()), System.Array[System.Byte](()))

    gen = mainMethod.GetILGenerator()

    # get the ScriptCode assembly...
    if config.embed:
        # put the generated DLL into the resources for the stub exe
        w = mb.DefineResource("IPDll.resources", "Embedded IronPython Generated DLL")
        w.AddResource("IPDll." + config.output, System.IO.File.ReadAllBytes(config.output + ".dll"))
        System.IO.File.Delete(config.output + ".dll")

        # generate code to load the resource
        gen.Emit(OpCodes.Ldstr, "IPDll")
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
        gen.Emit(OpCodes.Newobj, clr.GetClrType(System.Resources.ResourceManager).GetConstructor((str, clr.GetClrType(Assembly))))
        gen.Emit(OpCodes.Ldstr, "IPDll." + config.output)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Resources.ResourceManager).GetMethod("GetObject", (str, )), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Reflection.Assembly).GetMethod("Load", (clr.GetClrType(System.Array[System.Byte]), )), ())
    else:
        # variables for saving original working directory und return code of script
        wdSave = gen.DeclareLocal(str)

        # save current working directory
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Environment).GetMethod("get_CurrentDirectory"), ())
        gen.Emit(OpCodes.Stloc, wdSave)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(Assembly).GetMethod("get_Location"), ())
        gen.Emit(OpCodes.Newobj, clr.GetClrType(System.IO.FileInfo).GetConstructor( (str, ) ))
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.IO.FileInfo).GetMethod("get_Directory"), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.IO.DirectoryInfo).GetMethod("get_FullName"), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Environment).GetMethod("set_CurrentDirectory"), ())
        gen.Emit(OpCodes.Ldstr, config.output + ".dll")
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.IO.Path).GetMethod("GetFullPath", (clr.GetClrType(str), )), ())
        # result of GetFullPath stays on the stack during the restore of the
        # original working directory

        # restore original working directory
        gen.Emit(OpCodes.Ldloc, wdSave)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Environment).GetMethod("set_CurrentDirectory"), ())

        # for the LoadFile() call, the full path of the assembly is still is on the stack
        # as the result from the call to GetFullPath()
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Reflection.Assembly).GetMethod("LoadFile", (clr.GetClrType(str), )), ())

    # emit module name
    gen.Emit(OpCodes.Ldstr, "__main__")  # main module name
    gen.Emit(OpCodes.Ldnull)             # no references
    gen.Emit(OpCodes.Ldc_I4_0)           # don't ignore environment variables for engine startup

    # call InitializeModule
    # (this will also run the script)
    ctype=clr.GetClrType(PythonOps)
    print(dir(ctype))
    ops=ctype.GetMethod("InitializeModuleEx")
    gen.EmitCall(OpCodes.Call,ops, ())
    gen.Emit(OpCodes.Ret)
    tb.CreateType()
    ab.SetEntryPoint(mainMethod, config.target)
    ab.Save(aName.Name + ".exe", config.platform, config.machine)
Пример #3
0
def GenerateExe(config):
    """generates the stub .EXE file for starting the app"""
    aName = AssemblyName(System.IO.FileInfo(config.output).Name)

    if config.file_version is not None:
        aName.Version = Version(config.file_version)

    ab = PythonOps.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave)
    ab.DefineVersionInfoResource(config.file_info_product,
                                 config.file_info_product_version,
                                 config.file_info_company,
                                 config.file_info_copyright,
                                 config.file_info_trademark)

    mb = ab.DefineDynamicModule(config.output, aName.Name + ".exe")
    tb = mb.DefineType("PythonMain", TypeAttributes.Public)
    assemblyResolveMethod = None
    # 3/19/2018  # Copyright 2018 - hdunn. Apache 2.0 licensed. Modified from original.
    # --- handle dll and StdLib embed -----------
    dllNames = []
    if config.embed and config.dlls: #not for standalone ?
        config.dlls = list(set(config.dlls))
        opath = System.IO.Path.GetDirectoryName(config.output)
        for dll in config.dlls:
            dpath = System.IO.Path.GetFileName(dll)
            dllNames.append(dpath)
            lpath = System.IO.Path.Combine(opath,dpath)
            if '.dll' not in dll:
                try:
                    print 'Adding to Ref: ' + lpath
                    clr.AddReferenceToFileAndPath(lpath)
                except Exception as exa:
                    msg = ('File | Filepath: \n {}: ' +
                           'not a DLL file or does not exist.').format(dll)
                    raise IOError(str(exa) + '\n' + msg)

            elif '.dll' in dll:
                try:
                    print 'Adding .dll to Ref: ' + dll
                    clr.AddReferenceToFileAndPath(dll)
                except Exception as exb:
                    msg = ('File | Filepath: \n {}: ' +
                           'not a DLL file or does not exist.').format(dll)
                    raise IOError(str(exb) + '\n' + msg)
    
    outdir = System.IO.Path.GetDirectoryName(config.output)
    if config.standalone or config.libembed or config.embed:
        StdLibOutPath = System.IO.Path.Combine(outdir,'StdLib.dll')
        clrHasStdLib = False
        for clrRef in clr.References:
            if 'StdLib' in str(clrRef):
                clrHasStdLib = True
        # error if already so try
        if System.IO.File.Exists(StdLibOutPath) and not clrHasStdLib:
            try:
             clr.AddReferenceToFileAndPath(StdLibOutPath)
             clrHasStdLib = True
            except(System.IO.IOException, System.IO.FileLoadException) as exd:
                if exd.GetType()==System.IO.IOException:
                    msg = ('File | Filepath:\nStdLib.dll or {}:\n ' +
                           'Not a DLL file or does not exist.') \
                           .format(config.output + '.dll')
                    print msg
                elif exd.GetType()==System.IO.FileLoadException:
                    msg = ('File | Filepath: {}\n' +
                          'Not a clr Loadable file.') \
                          .format(config.output + '.dll')
                    print msg

        if not clrHasStdLib:

            try:
                clr.AddReference("StdLib.dll")
            except (System.IO.IOException, System.IO.FileLoadException) as ex:
                if ex.GetType()==System.IO.IOException:
                    msg = ('File | Filepath:\nStdLib.dll or {}:\n ' +
                           'Not a DLL file or does not exist.') \
                           .format(config.output + '.dll')
                    print msg
                elif ex.GetType()==System.IO.FileLoadException:
                    msg = ('File | Filepath: {}\n' +
                          'Not a clr Loadable file.') \
                          .format(config.output + '.dll')
                    print msg
            print
            print 'Trying to finish .... - check compiled function, paths and access'
            print

        config.embed = True

        # 3/19/2018,4/3/2018  # Copyright 2018 - hdunn. Apache 2.0 licensed. Modified from original.
        # ----- handle dll and StdLib embed -----------
        embedDict = {}
        for a in System.AppDomain.CurrentDomain.GetAssemblies():
            n = AssemblyName(a.FullName)

            if not a.IsDynamic and not a.EntryPoint:
                if config.standalone:
                    if n.Name.StartsWith("IronPython") or \
                        n.Name in ['Microsoft.Dynamic', 'Microsoft.Scripting']:
                        embedDict[n] = a

                # hdunn 3/15/2018 any(n.Name in dlln for dlln in dllNames) or \ above
                if any(n.Name in dlln for dlln in dllNames):
                    embedDict[n] = a
                if config.libembed and 'StdLib' in n.Name:
                    embedDict[n] = a

        for name, assem in embedDict.iteritems():
            print "\tEmbedding %s %s" % (name.Name, str(name.Version))
            print '  path:\n  ' + str(assem.Location)
            if assem.Location:
                print 'exists' + str(System.IO.File.Exists(assem.Location))
                if System.IO.File.Exists(assem.Location):
                    f = System.IO.FileStream(assem.Location, System.IO.FileMode.Open, System.IO.FileAccess.Read)    
                    mb.DefineManifestResource("Dll." + name.Name, f, ResourceAttributes.Public)

        # we currently do no error checking on what is passed in to the AssemblyResolve event handler
        assemblyResolveMethod = tb.DefineMethod("AssemblyResolve", MethodAttributes.Public | MethodAttributes.Static, clr.GetClrType(Assembly), (clr.GetClrType(System.Object), clr.GetClrType(System.ResolveEventArgs)))
        gen = assemblyResolveMethod.GetILGenerator()
        s = gen.DeclareLocal(clr.GetClrType(System.IO.Stream)) # resource stream
        gen.Emit(OpCodes.Ldnull)
        gen.Emit(OpCodes.Stloc, s)
        d = gen.DeclareLocal(clr.GetClrType(System.Array[System.Byte])) # data buffer
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
        gen.Emit(OpCodes.Ldstr, "Dll.")
        gen.Emit(OpCodes.Ldarg_1)    # The event args
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.ResolveEventArgs).GetMethod("get_Name"), ())
        gen.Emit(OpCodes.Newobj, clr.GetClrType(AssemblyName).GetConstructor((str, )))
        gen.EmitCall(OpCodes.Call, clr.GetClrType(AssemblyName).GetMethod("get_Name"), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(str).GetMethod("Concat", (str, str)), ())
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(Assembly).GetMethod("GetManifestResourceStream", (str, )), ())
        gen.Emit(OpCodes.Stloc, s)
        gen.Emit(OpCodes.Ldloc, s)
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.IO.Stream).GetMethod("get_Length"), ())
        gen.Emit(OpCodes.Newarr, clr.GetClrType(System.Byte))
        gen.Emit(OpCodes.Stloc, d)
        gen.Emit(OpCodes.Ldloc, s)
        gen.Emit(OpCodes.Ldloc, d)
        gen.Emit(OpCodes.Ldc_I4_0)
        gen.Emit(OpCodes.Ldloc, s)
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.IO.Stream).GetMethod("get_Length"), ())
        gen.Emit(OpCodes.Conv_I4)
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.IO.Stream).GetMethod("Read", (clr.GetClrType(System.Array[System.Byte]), int, int)), ())
        gen.Emit(OpCodes.Pop)
        gen.Emit(OpCodes.Ldloc, d)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("Load", (clr.GetClrType(System.Array[System.Byte]), )), ())
        gen.Emit(OpCodes.Ret)

        # generate a static constructor to assign the AssemblyResolve handler (otherwise it tries to use IronPython before it adds the handler)
        # the other way of handling this would be to move the call to InitializeModule into a separate method.
        staticConstructor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, System.Type.EmptyTypes)
        gen = staticConstructor.GetILGenerator()
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.AppDomain).GetMethod("get_CurrentDomain"), ())
        gen.Emit(OpCodes.Ldnull)
        gen.Emit(OpCodes.Ldftn, assemblyResolveMethod)
        gen.Emit(OpCodes.Newobj, clr.GetClrType(System.ResolveEventHandler).GetConstructor((clr.GetClrType(System.Object), clr.GetClrType(System.IntPtr))))
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(System.AppDomain).GetMethod("add_AssemblyResolve"), ())
        gen.Emit(OpCodes.Ret)

    mainMethod = tb.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, int, ())
    if config.target == System.Reflection.Emit.PEFileKinds.WindowApplication and config.mta:
        mainMethod.SetCustomAttribute(clr.GetClrType(System.MTAThreadAttribute).GetConstructor(()), System.Array[System.Byte](()))
    elif config.target == System.Reflection.Emit.PEFileKinds.WindowApplication:
        mainMethod.SetCustomAttribute(clr.GetClrType(System.STAThreadAttribute).GetConstructor(()), System.Array[System.Byte](()))

    gen = mainMethod.GetILGenerator()

    # get the ScriptCode assembly...
    if config.embed:

        # put the generated DLL into the resources for the stub exe
        w = mb.DefineResource("IPDll.resources", "Embedded IronPython Generated DLL")
        # print 'IPDLL NAME: ' + 'IPDLL.' + config.output
        # 4/4/2018 Copyright 2018 - hdunn. Apache 2.0 licensed. Modified from original.----- IPDLL NAME
        strPathRefIPDll = System.IO.DirectoryInfo(config.output).Name
        #---  'Changed to: ' + "IPDll." + strPathRefIPDll
        # comment out System.IO.File.Exists(config.output + ".dll"))
        # w.AddResource("IPDll." + config.output, System.IO.File.ReadAllBytes(config.output + ".IPDLL"))
        w.AddResource("IPDll." + strPathRefIPDll, System.IO.File.ReadAllBytes(config.output + ".IPDLL"))
        #--------------------
        # generate code to load the resource
        gen.Emit(OpCodes.Ldstr, "IPDll")
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
        gen.Emit(OpCodes.Newobj, clr.GetClrType(System.Resources.ResourceManager).GetConstructor((str, clr.GetClrType(Assembly))))
        # ---- hdunn dido --------
        gen.Emit(OpCodes.Ldstr, "IPDll." + strPathRefIPDll)#strPathRefIPDll)#config.output 4/4
        # ------------------
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Resources.ResourceManager).GetMethod("GetObject", (str, )), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Reflection.Assembly).GetMethod("Load", (clr.GetClrType(System.Array[System.Byte]), )), ())
        if config.verbose: print 'Base embed... completed {}'.format(config.output + ".dll")

    else:

        if config.verbose: print 'No embed'
        # variables for saving original working directory und return code of script
        wdSave = gen.DeclareLocal(str)

        # save current working directory
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Environment).GetMethod("get_CurrentDirectory"), ())
        gen.Emit(OpCodes.Stloc, wdSave)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(Assembly).GetMethod("GetEntryAssembly"), ())
        gen.EmitCall(OpCodes.Callvirt, clr.GetClrType(Assembly).GetMethod("get_Location"), ())
        gen.Emit(OpCodes.Newobj, clr.GetClrType(System.IO.FileInfo).GetConstructor((str, )))
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.IO.FileInfo).GetMethod("get_Directory"), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.IO.DirectoryInfo).GetMethod("get_FullName"), ())
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Environment).GetMethod("set_CurrentDirectory"), ())
        # 4.11.2018 Copyright 2018 - hdunn. Apache 2.0 licensed. Modified from original.
        strPathRefDll = System.IO.DirectoryInfo(config.output).Name + '.dll'
        gen.Emit(OpCodes.Ldstr, strPathRefDll)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.IO.Path).GetMethod("GetFullPath", (clr.GetClrType(str), )), ())
        # result of GetFullPath stays on the stack during the restore of the
        # original working directory
        # restore original working directory
        gen.Emit(OpCodes.Ldloc, wdSave)
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Environment).GetMethod("set_CurrentDirectory"), ())

        # for the LoadFile() call, the full path of the assembly is still is on the stack
        # as the result from the call to GetFullPath()
        gen.EmitCall(OpCodes.Call, clr.GetClrType(System.Reflection.Assembly).GetMethod("LoadFile", (clr.GetClrType(str), )), ())

    # emit module name
    if config.verbose: print 'emit main ... '
    gen.Emit(OpCodes.Ldstr, "__main__")  # main module name
    gen.Emit(OpCodes.Ldnull)             # no references
    gen.Emit(OpCodes.Ldc_I4_0)           # don't ignore environment variables for engine startup

    # call InitializeModule
    # (this will also run the script)
    # -------------------------------------
    # 3.10.2018 Copyright 2018 - hdunn. Apache 2.0 licensed. Modified from original.
    Init_Long = None
    for mi in clr.GetClrType(PythonOps).GetMethods():
        if "InitializeModuleEx" in mi.Name and len(mi.GetParameters()) == 4:
            Init_Long = mi
    gen.EmitCall(OpCodes.Call, Init_Long, ())
    # -------------------------------------
    gen.Emit(OpCodes.Ret)
    tb.CreateType()
    ab.SetEntryPoint(mainMethod, config.target)
    ab.Save(aName.Name + ".exe", config.platform, config.machine)
    if config.verbose: print 'Gen emit ... done'
    if config.verbose: print "Save as " +  aName.Name + ".exe"
    System.IO.File.Delete(config.output + ".IPDLL")