O CÓDIGO FONTE DO PYTHON

Muitos desenvolvedores trabalham com uma linguagem por anos sem nunca baixar o código-fonte do interpretador ou compilador, mesmo estando disponível a todos. Podemos tanto acessar o código pelo navegador, ou baixa-lo com alguma ferramenta de versionamento de código como o Git ou então o Mercurial. Também existe a opção de baixar todo o pacote num arquivo compactado no site oficial do repositório onde os códigos estão disponibilizados.

Conheço essa realidade por experiência própria! Raríssimas foram as vezes em que baixei e analisei o código das ferramentas de código aberto que utilizei e, na maioria das vezes em que fiz o downloads do fontes para o disco local, foi porque o tutorial que estava utilizando exigia.

Até pouco tempo o Python utiliza o sistema de gerenciamento de versão Mercurial, porém, em vista de que o git se tornou por livre adoção dos desenvolvedores quase que um padrão, o código de todo o interpretador do Python e suas bibliotecas agora estão no Github e o mesmo se tornou o repositório oficial do projeto.

Antes de acessarmos os repositório, é importante dizer, ou então relembrar, que o interpretador oficial do Python se chama CPython. Não é difícil de perceber que o caractere C a frente do nome Python indica que essa versão do interpretador foi escrita com a linguagem C.

O ENTRY POINT

O Entry Point ou o ponto de entrada de uma aplicação é a nomenclatura utilizada para se referir a primeira função que é invocada na execução de um Script ou de uma aplicação.

O interpretador do Python, por padrão, foi e continua sendo desenvolvido em C. No entanto, nem todos os módulos que chamamos de nativos são desenvolvidos em C e também, nem todos os módulos contidos numa instalação padrão foram escritos pela equipe de desenvolvedores do Python.

Por exemplo, o SQLite está contido por padrão em todas versões do Python, o mesmo utiliza somente código C, porém, o seu desenvolvimento é feito por outro grupo de desenvolvedores.

O código a seguir é o ponto inicial do interpretador do Python, ou seja, é por essa função que o interpretador inicia a execução.

main(int argc, char **argv)
{
    wchar_t **argv_copy;
    /* We need a second copy, as Python might modify the first one. */
    wchar_t **argv_copy2;
    int i, res;
    char *oldloc;

    /* Force malloc() allocator to bootstrap Python */
#ifdef Py_DEBUG
    (void)_PyMem_SetupAllocators("malloc_debug");
#  else
    (void)_PyMem_SetupAllocators("malloc");
#  endif

    argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1));
    argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1));
    if (!argv_copy || !argv_copy2) {
        fprintf(stderr, "out of memory\n");
        return 1;
    }

    /* 754 requires that FP exceptions run in "no stop" mode by default,
     * and until C vendors implement C99's ways to control FP exceptions,
     * Python requires non-stop mode.  Alas, some platforms enable FP
     * exceptions by default.  Here we disable them.
     */
#ifdef __FreeBSD__
    fedisableexcept(FE_OVERFLOW);
#endif

    oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL));
    if (!oldloc) {
        fprintf(stderr, "out of memory\n");
        return 1;
    }

#ifdef __ANDROID__
    /* Passing "" to setlocale() on Android requests the C locale rather
     * than checking environment variables, so request C.UTF-8 explicitly
     */
    setlocale(LC_ALL, "C.UTF-8");
#else
    /* Reconfigure the locale to the default for this process */
    setlocale(LC_ALL, "");
#endif

    if (_Py_LegacyLocaleDetected()) {
        _Py_CoerceLegacyLocale();
    }

    /* Convert from char to wchar_t based on the locale settings */
    for (i = 0; i < argc; i++) {
        argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
        if (!argv_copy[i]) {
            PyMem_RawFree(oldloc);
            fprintf(stderr, "Fatal Python error: "
                            "unable to decode the command line argument #%i\n",
                            i + 1);
            return 1;
        }
        argv_copy2[i] = argv_copy[i];
    }
    argv_copy2[argc] = argv_copy[argc] = NULL;

    setlocale(LC_ALL, oldloc);
    PyMem_RawFree(oldloc);

    res = Py_Main(argc, argv_copy);

    /* Force again malloc() allocator to release memory blocks allocated
       before Py_Main() */
#ifdef Py_DEBUG
    (void)_PyMem_SetupAllocators("malloc_debug");
#  else
    (void)_PyMem_SetupAllocators("malloc");
#  endif

    for (i = 0; i < argc; i++) {
        PyMem_RawFree(argv_copy2[i]);
    }
    PyMem_RawFree(argv_copy);
    PyMem_RawFree(argv_copy2);
    return res;
}
#endif

Caso queiras ir no repositório onde estão os códigos fontes do Python e analisar todo o módulo, utilize este link que lhe direcionará a função em C que imprimimos acima.



Tags python, c, cpp, python.c, entry point, ponto de entrada

Comentários

comments powered by Disqus