Python ha un compilatore! Semplicemente non te ne accorgi perché funziona automaticamente. Puoi dire che è lì, però: guarda .pyc
(o .pyo
se hai attivato l'ottimizzatore) i file che vengono generati per i moduli che tu import
.
Inoltre, non si compila con il codice della macchina nativa. Invece, compila un codice byte che viene utilizzato da una macchina virtuale. La macchina virtuale è essa stessa un programma compilato. Questo è molto simile a come funziona Java; così simile, infatti, che esiste una variante Python ( Jython ) che invece compila il codice byte della Java Virtual Machine! C'è anche IronPython , che viene compilato con il CLR di Microsoft (usato da .NET). (Il normale compilatore di codice byte Python è talvolta chiamato CPython per disambigerlo da queste alternative.)
C ++ deve esporre il suo processo di compilazione perché il linguaggio stesso è incompleto; non specifica tutto ciò che il linker deve sapere per creare il tuo programma, né può specificare le opzioni di compilazione in modo portabile (alcuni compilatori ti permettono di usare #pragma
, ma non è standard). Quindi devi fare il resto del lavoro con makefile e possibilmente l'inferno automatico (autoconf / automake / libtool). Questo è davvero solo un retaggio da come C l'ha fatto. E C l'ha fatto in questo modo perché rendeva il compilatore semplice, il che è uno dei motivi principali per cui è così popolare (chiunque potrebbe sfornare un semplice compilatore C negli anni '80).
Alcune cose che possono influenzare l'operazione del compilatore o del linker ma non sono specificate nella sintassi di C o C ++:
- risoluzione delle dipendenze
- requisiti della libreria esterna (incluso l'ordine di dipendenza)
- livello di ottimizzazione
- impostazioni di avviso
- versione della specifica del linguaggio
- mappature del linker (che sezione va dove nel programma finale)
- architettura di destinazione
Alcuni di questi possono essere rilevati, ma non possono essere specificati; per esempio. Sono in grado di rilevare quale C ++ è in uso con __cplusplus
, ma non posso specificare che C ++ 98 sia quello utilizzato per il mio codice all'interno del codice stesso; Devo passarlo come un flag al compilatore nel Makefile, o creare un'impostazione in una finestra di dialogo.
Sebbene si possa pensare che esista un sistema di "risoluzione delle dipendenze" nel compilatore, generando automaticamente dei record di dipendenza, questi record indicano solo i file di intestazione utilizzati da un dato file sorgente. Non possono indicare quali moduli aggiuntivi del codice sorgente sono necessari per collegarsi a un programma eseguibile, perché non esiste un modo standard in C o C ++ per indicare che un determinato file di intestazione è la definizione di interfaccia per un altro modulo di codice sorgente anziché solo un gruppo di linee che vuoi mostrare in più punti in modo da non ripeterti. Ci sono tradizioni nelle convenzioni sui nomi dei file, ma queste non sono conosciute o applicate dal compilatore e dal linker.
Molti di questi possono essere impostati usando #pragma
, ma questo non è standard, e stavo parlando dello standard. Tutte queste cose potrebbero essere specificate da uno standard, ma non sono state nell'interesse della retrocompatibilità. La saggezza prevalente è che i makefile e gli IDE non sono danneggiati, quindi non risolverli.
Python gestisce tutto questo nella lingua. Ad esempio, import
specifica una dipendenza del modulo esplicita, implica la struttura di dipendenza e i moduli non sono suddivisi in file di intestazione e di origine (cioè interfaccia e implementazione).