Python tem um compilador! Você simplesmente não percebe porque é executado automaticamente. Você pode dizer que está lá: veja os arquivos .pyc
(ou .pyo
se o otimizador estiver ativado) que são gerados para os módulos que você import
.
Além disso, ele não é compilado no código da máquina nativa. Em vez disso, ele compila para um código de bytes usado por uma máquina virtual. A máquina virtual é ela própria um programa compilado. Isso é muito parecido com o funcionamento do Java; tão semelhante, de fato, que existe uma variante Python ( Jython ) que compila o código de bytes da Java Virtual Machine! Há também o IronPython , que compila com o CLR da Microsoft (usado pelo .NET). (O compilador de código de bytes Python normal às vezes é chamado de CPython para desambiguá-lo dessas alternativas.)
O C ++ precisa expor seu processo de compilação porque a própria linguagem está incompleta; ele não especifica tudo o que o vinculador precisa saber para criar seu programa, nem pode especificar opções de compilação de forma portável (alguns compiladores permitem que você use #pragma
, mas isso não é padrão). Então você tem que fazer o resto do trabalho com makefiles e possivelmente com o inferno automático (autoconf / automake / libtool). Este é realmente apenas um resquício de como C fez isso. E C fez dessa maneira porque simplificou o compilador, o que é um dos principais motivos pelos quais ele é tão popular (qualquer um poderia criar um compilador C simples nos anos 80).
Algumas coisas que podem afetar a operação do compilador ou vinculador, mas não são especificadas na sintaxe do C ou C ++:
- resolução de dependência
- requisitos de biblioteca externa (incluindo ordem de dependência)
- nível otimizador
- configurações de aviso
- versão de especificação de idioma
- mapeamentos de vinculador (qual seção vai para onde no programa final)
- arquitetura de destino
Alguns deles podem ser detectados, mas não podem ser especificados; por exemplo, eu posso detectar com qual C ++ está sendo usado __cplusplus
, mas não posso especificar que C ++ 98 é aquele usado para o meu código no próprio código; Eu tenho que passá-lo como um sinalizador para o compilador no Makefile, ou fazer uma configuração em uma caixa de diálogo.
Embora você possa pensar que existe um sistema de "resolução de dependência" no compilador, gerando automaticamente registros de dependência, esses registros dizem apenas quais arquivos de cabeçalho um determinado arquivo de origem usa. Eles não podem indicar quais módulos de código-fonte adicionais são necessários para vincular a um programa executável, porque não há uma maneira padrão em C ou C ++ para indicar que um determinado arquivo de cabeçalho é a definição de interface para outro módulo de código-fonte, em vez de apenas um monte de linhas que você deseja exibir em vários lugares para não se repetir. Existem tradições nas convenções de nomenclatura de arquivos, mas elas não são conhecidas ou impostas pelo compilador e vinculador.
Vários deles podem ser definidos usando #pragma
, mas isso não é padrão, e eu estava falando sobre o padrão. Todas essas coisas podem ser especificadas por um padrão, mas não têm o interesse de compatibilidade com versões anteriores. A sabedoria predominante é que makefiles e IDEs não estão quebrados, então não os conserte.
Python lida com tudo isso na linguagem. Por exemplo, import
especifica uma dependência explícita do módulo, implica a árvore de dependências e os módulos não são divididos em arquivos de cabeçalho e de origem (por exemplo, interface e implementação).