Python ha un compilatore! Non te ne accorgi perché funziona automaticamente. Puoi dire che è lì, però: guarda i file .pyc
(o .pyo
se hai l'ottimizzatore attivato) che vengono generati per i moduli che hai import
.
Inoltre, non viene compilato nel codice della macchina nativa. Al contrario, si compila in un codice byte 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 di Python ( Jython ) che si compila invece nel codice byte della Java Virtual Machine! C'è anche IronPython , che si compila in CLR di Microsoft (usato da .NET). (Il normale compilatore di codice byte Python viene talvolta chiamato CPython per chiarire la sua ambiguità da queste alternative.)
Il C ++ deve esporre il suo processo di compilazione perché il linguaggio stesso è incompleto; non specifica tutto ciò che il linker deve sapere per costruire il tuo programma, né può specificare portabilmente le opzioni di compilazione (alcuni compilatori ti permettono di usare #pragma
, ma non è standard). Quindi devi fare il resto del lavoro con makefile e possibilmente auto hell (autoconf / automake / libtool). Questo è davvero solo un holdover da come C ha fatto. E C lo ha fatto in questo modo perché ha reso semplice il compilatore, che è uno dei motivi principali per cui è così popolare (chiunque potrebbe creare un semplice compilatore C negli anni '80).
Alcune cose che possono influire sul funzionamento 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 specifica della lingua
- mappature dei linker (quale sezione va dove nel programma finale)
- architettura target
Alcuni di questi possono essere rilevati, ma non possono essere specificati; ad esempio, posso rilevare con quale C ++ è in uso __cplusplus
, ma non posso specificare che C ++ 98 è quello utilizzato per il mio codice all'interno del codice stesso; Devo passarlo come flag al compilatore nel Makefile o fare un'impostazione in una finestra di dialogo.
Sebbene si possa pensare che esista un sistema di "risoluzione delle dipendenze" nel compilatore, che genera automaticamente i record di dipendenza, questi record indicano solo quali file di intestazione vengono utilizzati da un determinato file di origine. Non possono indicare quali moduli di codice sorgente aggiuntivi sono necessari per il collegamento in un programma eseguibile, poiché non esiste un modo standard in C o C ++ per indicare che un determinato file di intestazione è la definizione dell'interfaccia per un altro modulo di codice sorgente, a differenza di un solo gruppo di linee che desideri mostrare in più punti in modo da non ripetere te stesso. Esistono tradizioni nelle convenzioni di denominazione 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 rotti, quindi non risolverli.
Python gestisce tutto questo nella lingua. Ad esempio, import
specifica una dipendenza esplicita del modulo, implica l'albero delle dipendenze e i moduli non sono suddivisi in file di intestazione e di origine (ovvero interfaccia e implementazione).