em Português, programação, Python, windows

Como criar um executável com Instalador MSI em Python

Esse post é o primeiro da série Distribuir Programas em Python para Desktops Windows. Esse é o mais básico de todos, e esse assunto já foi bem discutido em diversos sites, mas a minha ideia aqui é apresentar como criei o programa de exemplo, mostrar como posso gerar um instalador bem simples já com as bibliotecas que o programa precisa pra rodar em outros Windows.

Toda vez que você gera um executável em Python, o windows precisa das DLLs de Runtime do C++, o tal do Microsoft Visual C++ Redistributable, você vai encontrar como MSVCR. A versão que será necessária depende de qual versão do Python você está usando.

Nós temos três coisas a fazer:

  1. Criar o script do programa
  2. Criar um arquivo de setup para gerar o executável.
  3. Gerar o Instalador MSI

Vou criar um script besta em python só pra ilustrar esses posts, isso é de uma brincadeira idiota que fiz com um amigo meu. Toda vez que o usuário apertar Print Screen o aplicativo vai abrir uma foto de uma boneca, como da foto abaixo:

baby-looking-like-his-doll

 


#boneca.py
import os
import sys
import ctypes
from ctypes import wintypes
import win32con

byref = ctypes.byref
user32 = ctypes.windll.user32

HOTKEYS = {
    1 : (win32con.VK_SNAPSHOT, 0), ####Essa Linha Pega a tecla "PRINT SCREEN"
    2 : (win32con.VK_F4, win32con.MOD_WIN)
}

def handle_win_f3 ():
    os.startfile(os.path.join(os.path.realpath(os.path.dirname(sys.argv[0])),"boneca.jpg"))

def handle_win_f4 ():
    user32.PostQuitMessage (0)

HOTKEY_ACTIONS = {
    1 : handle_win_f3,
    2 : handle_win_f4
}


# Registrando as chaves sem dar o print pra ficar escondido na tela.
for id, (vk, modifiers) in HOTKEYS.items ():
    #print "Registering id", id, "for key", vk
    pass
    if not user32.RegisterHotKey (None, id, modifiers, vk):
        #print "Unable to register id", id
        pass


# Executando as funções e tirando o registro das chaves depois do encerramento do programa.
try:
    msg = wintypes.MSG ()
    while user32.GetMessageA (byref (msg), None, 0, 0) != 0:
        if msg.message == win32con.WM_HOTKEY:
            action_to_take = HOTKEY_ACTIONS.get (msg.wParam)
            if action_to_take:
                action_to_take ()

        user32.TranslateMessage (byref (msg))
        user32.DispatchMessageA (byref (msg))

finally:
    for id in HOTKEYS.keys ():
        user32.UnregisterHotKey (None, id)

Como referência pra esse código eu usei o post do Tim Golden[1].

O código é simples, ele cria dois atalhos no windows, um é o Print Screen que quando pressionado roda a função handle_win_f3 que faz a chamada da foto da boneca.jpg

Já quando ele pressionar o atalho Win + F4 será executada a função handle_win_f4 que apenas encerra o programa. Ele não tem interface gráfica, o que faz sentido pra essa brincadeira.

Beleza, até aí só um script python fácil, agora nós precisamos fazer o Frozen dessa aplicação. Gerar um Frozen (um módulo congelado) é compilar o script e gerar um executável que contenha o interpretador python, suas bibliotecas, seu script e seus arquivos tudo em um lugar só e com um executável (ou mais executáveis). Para isso você precisa criar um arquivo de setup e escolher uma ferramenta para fazer o frozen, os mais usados são py2exe, py2app, cx_freeze, e o pyinstaller. Nesse caso eu vou usar o cx_freeze. Esse arquivo por convenção é chamado de setup.py e


#setup.py
from cx_Freeze import setup, Executable

setup(
    name = "boneca",
    version = "1.0.0",
    options = {"build_exe": {
        'packages': ["os","sys","ctypes","win32con"],
        'include_files': ['boneca.jpg'],
        'include_msvcr': True,
    }},
    executables = [Executable("boneca.py",base="Win32GUI")]
    )

O script também é simples, ele segue a mesma lógica do disutils , só quero chamar atenção para o include_msvcr que vai colocar as DLLs do Microsoft Visual C++ Redistributable no seu executável, dessa forma ele vai copiar as DLLs que já existem no seu sistema operacional. Esse é o único jeito do seu programa funcionar em outros windows, pois o Python precisa dessas dlls para ser executado. Você também pode baixar o próprio instalador do MSVCR da Microsoft e incorporar no seu instalador usando o Inno Setup, por exemplo, vou mostrar isso em um dos próximos posts da série.

Agora vamos gerar um MSI, ou seja, um instalador para windows. Só rodar na linha de comando:

python setup.py bdist_msi

Beleza, agora ele criou uma pasta chamada dist com um arquivo boneca-1.0.0-win32.msi (ou boneca-1.0.0-amd64.msi se seu sistema for 64) agora já dá pra instalar e usar. Então aqui mostrei Como criar um executável com Instalador MSI em Python e com Cx_freeze.

Os scripts estão no meu Github: https://github.com/ffreitasalves/boneca

[1]: http://timgolden.me.uk/python/win32_how_do_i/catch_system_wide_hotkeys.html

Escreva um comentário

Comentário

20 Comentários

  1. Obrigado pelo tutorial, muito bom.
    Eu estou com um problema, o cx_Freeze não está importando as bibliotecas do PyQt5, eu as incluo no script do setup mas não adianta.
    Isso já aconteceu com vc ?

    • Cara, não usei com o PyQt5, usei com o PySide (equivalente ao PyQT4) e coloquei no includes = [‘PySide’,], no setup.py e no options do setup eu colocava desse jeito aqui:

      from cx_Freeze import setup

      includes = [‘PySide’,]

      setup(

      options={“build_exe”:
      {“packages”:packages,
      “includes”: includes,
      “include_files”: include_files,
      “excludes”: excludes,
      “optimize”: 2,
      “icon”:”icon-16px.ico”,
      },
      “bdist_esky”:{
      ‘freezer_module’:”cxfreeze”,
      ‘includes’: includes,
      ‘excludes’: excludes,
      },

      )

  2. Caro Fernando,

    Você saberia me dizer se há algo que precisaria ser modificado no setup.py caso o programa desenvolvido em Python não tenha interface GUI, sendo somente console?

    É que usei o seu tutorial pra empacotar uma aplicação que estou desenvolvendo aqui, mas ao tentar executar o arquivo .exe gerado, tenho este erro retornado.

    Saberia, só com base nisso, me dizer se fiz algo errado?

    Grato!

    • Fala ae Fabrício. Primeiro, no setup.py vc tá usando o quê? py2exe ou cx_freeze? Se for o py2exe fica super fácil é só criar um arquivo mais ou menos assim:

      
         1 from distutils.core import setup
         2 import py2exe
         3 
         4 setup(console=['hello.py'])
      

      Se estiver usando o esky como eu mostrei é só trocar o gui_only pra False
      Se for com o cx_freeze é só tirar o argumento base=base, (pq to usando um base=Win32Gui mas o default é um que usa o console)
      E o erro é de importação, você precisa colocar as dependências na lista de packages (no caso o configparser).

      []’s

  3. Olá, eu tenho um executável de um código que um colega me passou, porem em minha pesquisa tenho que realizar algumas modificações no código, existe alguma maneira de realizar essas modificações sem o código fonte?

  4. Muito obrigado pelo tutorial, bem simples e eficaz. Entretanto, eu to tendo um erro aqui, e queria pedir sua ajuda, o erro é o seguinte:

    Traceback (most recent call last):
    File “setup.py”, line 2, in
    from cx_Freeze import setup, Executable
    File “C:\Python27\lib\site-packages\cx_Freeze\__init__.py”, line 10, in
    from cx_Freeze.freezer import *
    File “C:\Python27\lib\site-packages\cx_Freeze\freezer.py”, line 11, in
    import socket
    File “C:\Python27\lib\socket.py”, line 47, in
    import _socket
    ImportError: DLL load failed: Não foi possível encontrar o procedimento especificado.

  5. Boa tarde Fernando. Que grande post esse seu sobre executáveis Python.
    Gostaria de tirar uma dúvida se possível.

    com relação as dll MSVCR. A versão a utilizar vai de acordo com a versão do python ou com a versão do SO que estará no computador? Pelo que entendi a versão Microsoft Visual C++ 2008 Redistributable Package irá funcionar em qualquer computador desde que eu esteja utilizando python 2.6++. Entendi corretamente?

  6. fernando, boa tarde

    estou desenvolvendo um app que utliza wxpython e outros modulos e a tentativa de distribuir aqui na firma tem sido frustrante pois é para windows (msm se fosse linux muitas vezes não tem a versão correta)

    eu consigo fazer o executável seja utilizando o cxfreeze ou pyinstaller mas eles ativam o antivírus e não consigo. Será que criando o msi para instalar efetivamente faz com que o antivírus pare de encher o saco?

    Vlw

  7. Boa noite ffreitasalves:
    escrevo para vc porque rodei o seu script e deu todo bem mas rodei o meu que tem o PyQt4 no meio e deu erro num modulo de PyQt4 chamado ‘PyQt4.uic.port_v3.proxy_base’, o que vc aconselha nesse caso ?

  8. Olá Fernando,
    Primeiramente seu tutorial é muito bom, está de parabéns pelo trabalho. Sou iniciante com python (na programação em si), e estou trabalhando seguidamente com PyQt5. Provavelmente ainda terei que usar o conhecimento que compartilhou. Então, gostaria de saber com relação a programas que contenham banco de dados..Acredito que ele não será importado e terei que instalar no usuário?..é isso, desculpe minha ignorância, pois pretendo usar o MySQL ou o Postgres…O que vc indica fazer nesse caso?

  9. Muito obrigado Robson.
    Robson, eu acho que instalar o postgres ou mysql no computador do usuário é pesado demais, mas depende do tipo de programa que você está desenvolvendo. Se é necessário usar um banco de dados local e por usuário eu pensaria em utilizar o sqlite mesmo.
    No caso de ter que usar um outro banco de dados, você poderia configurar seu BD online e o seu programa acessar esse outro host para o banco de dados.
    E nos outros casos, como um programa mais técnico que pode ser usado por administradores e gerentes de rede, normalmente esses profissionais estão acostumados com programas nos quais eles são obrigados a instalar um banco de dados para funcionar junto com o programa, então poderia apenas descrever os passos de como instalar o banco e seu programa criaria as tabelas, depois de receber um usuário e senha.
    Se você der uma olhada no próximo passo do tutorial você também vai ver como usar o inno setup para distribuir seu programa e eu acredito que você consegue colocar o mysql ou o postgres para instalar juntamente com o programa!

    um abraço!

Webmentions

  • How to create a Python .exe with MSI Installer and Cx_freeze - Fernando Alves novembro 14, 2015

    […] It was originally published in Portuguese. […]

  • Como criar um programa com Auto-Update utilizando Python e Esky novembro 14, 2015

    […] Essa é a segunda parte da série de Posts Distribuir Programas em Python para Desktops Windows. Se quiser, veja o primeiro post: Como criar um executável com Instalador MSI em Python […]

  • Distribuir Programas em Python para Desktops Windows novembro 14, 2015

    […] Como criar um executável com Instalador MSI com Python e Cx_freeze […]