Si deve scrivere più "sapori" di codice C / C ++ per ogni piattaforma prevista?

3

Ho progettato ciò che ritengo sia una funzionalità utile e riutilizzabile che vorrei:

  1. Implementare in C / C ++ come libreria open source; e poi
  2. Scrivi diverse " librerie di binding nativo " per questo in vari linguaggi di livello superiore, in modo che gli utenti finali che scrivono applicazioni in questi linguaggi (Java, Ruby, Python, C #, Haskell, ecc.) possano tutti chiamano lo stesso codice C / C ++ sotto il cofano, ma guidano quel codice all'interno di queste librerie.

Ad esempio, potrei avere il seguente codice C:

// Pseudo-code for simple example only, don't read into this too much!
float square(float x) {
    float p;
    p = x * x;

    return p;
}

E poi scrivi una "libreria di rilegatura Java" che include il codice C compilato come libreria nativa all'interno del JAR e che espone un'API Java per invocarlo:

// Pseudo-code for simple example only, don't read into this too much!
public class SquareManager {
    public SquareManager() {
        super();

        System.loadLibrary("Square");
    }

    public native float square(float x);

    public float calcSquare(float x) {
        return square(x);
    }
}

Idem per altri linguaggi di alto livello (ancora, Ruby, Python, ecc.).

Quando sento persone che parlano di scrivere codice C / C ++, spesso li sento parlare di targeting varie piattaforme . Con questo, presumo significano che, con C / C ++, devi compilare il codice in binari che possono essere eseguiti su varie combinazioni di OS / set di istruzioni. Ad esempio, potresti avere una distribuzione binaria per l'esecuzione su Windows / x86. Potresti averne un altro per funzionare su Linux / x86. Si potrebbe anche avere una distribuzione per l'esecuzione su Linux / ARM. Quindi per cominciare, se l'affermazione sopra è imprecisa, per favore inizia correggendomi!

Supponendo che io sia più o meno corretto lì, allora mi sembra che dovrei essere in grado di:

  • Basta scrivere questo codice C / C ++ una volta; e poi
  • Assicurati, per ogni piattaforma (OS / set di istruzioni combinate) che voglio targetizzare, che io abbia un compilatore in esecuzione sulla mia macchina che possa compilare quel codice C / C ++ in un binario che può essere eseguito in modo nativo sul target piattaforma

Ciò sarebbe contrario a ciò di cui sono preoccupato, il che sarebbe una situazione in cui:

  • Per qualche ragione, ho bisogno di scrivere una versione / sapore differente del codice C / C ++ per ogni piattaforma mirata; e poi
  • Compilare ciascuna versione del codice sorgente in un file binario che può essere eseguito sulla piattaforma desiderata

Quindi chiedo: Sono corretto qui, pensando di poter scrivere il codice C / C ++ una volta, e poi semplicemente compilarlo (probabilmente usando diversi compilatori, o diverse configurazioni di compilatore) più volte, una volta per ogni piattaforma mirata che voglio sostenere? E se sono errato o fuorviato, qui, allora come?

    
posta smeeb 30.03.2017 - 15:03
fonte

4 risposte

9

Se stai attento a scrivere codice neutro rispetto alla piattaforma, potresti scrivere una versione C ++ e compilarla diverse volte. Non prenderei nessuna scommessa per ottenere il 100%.

Ciò che è più comune è che il 90% del codice è neutrale rispetto alla piattaforma e il resto finisce in sezioni controllate da direttive di compilazione condizionale, impostate per includere o escludere versioni diverse del codice sorgente a seconda della piattaforma. A volte queste sezioni sono molto brevi.

Perché sarebbero necessari? Le API di Windows non esistono nelle API Linux e Linux non esistono in Windows, ad esempio. Ci sono delle differenze nel modo in cui gli O / S programmano i thread e gestiscono la memoria, quindi potrebbero esserci sottili differenze nel modo in cui gestisci i blocchi o le maniglie. Se hai qualche struttura sindacale, potrebbe dover essere riorganizzata a seconda dell'endianness. Ecc.

Ho visto gruppi di prodotti che alla fine decidono di suddividere le loro basi di codice solo perché c'erano così tante eccezioni. E ho visto altre squadre cercare di unirle di nuovo. Non penso che ci sia una soluzione perfetta. Ma non c'è nulla di male nell'iniziare i tuoi sforzi con un singolo codice base, solo per vedere se è possibile.

    
risposta data 30.03.2017 - 15:45
fonte
4

La risposta è: Forse .

Ci sono davvero due aspetti nella tua domanda.

C++ Language

As long as you target a particular version of the C++ specification (say, C++ 11) and find a compiler on each platform that supports it, everything should just work (in theory).

The reality is that compilers can have bugs in them or may interpret the specification slightly differently so it's possible that your C++ code may compile correctly with one compiler but not another.

Consuming platform specific libraries

The challenge in cross-platform development comes when you start writing real world code that needs to use things not covered in the C++ specification (like sockets). This code is going to be different for each platform.

There are cross-platform libraries that are available to do these things for you (boost and QT are two examples I know of). You just need to make sure that they support the same compilers and platforms that you want to target.

In definitiva ciò che si finisce è il seguente:

  • Il tuo codice sorgente C ++
  • Libreria multipiattaforma di terze parti
  • Un sistema di compilazione per ogni piattaforma scelta come target (file di progetto di Visual Studio, creazione di file, ecc.)

Anche se si scrive codice C ++ esattamente secondo le specifiche C ++ e si trova una libreria multipiattaforma che supporta tutte le piattaforme che si desidera targetizzare, sarà comunque necessario scrivere un codice specifico per piattaforma per coprire uno dei seguenti:

  • Diverse interpretazioni dello standard C ++
  • Bug nella libreria multipiattaforma
  • Differenze di comportamento su una piattaforma rispetto a un'altra quando si richiamano funzioni di libreria specifiche

Il codice specifico della piattaforma viene solitamente scritto usando una direttiva pre-processore in modo da poter avere un singolo set di codice sorgente che compili per tutte le piattaforme.

    
risposta data 30.03.2017 - 16:06
fonte
1

Am I correct here, thinking that I can write the C/C++ code one time, and then simply compile it (probably using different compilers, or different compiler configs) multiple times, one time for each targeted platform I want to support? And if I'm incorrect or misled, here, then how?

Dipende molto dalla funzionalità che vuoi fornire. Né C né C ++ forniscono molto supporto alla libreria standard per tutto ciò che riguarda la grafica, l'audio, il networking, la gestione dei file, le comunicazioni tra interpreti e così via, quindi è necessario affidarsi a estensioni specifiche della piattaforma o strumenti di terze parti per supportarlo. Ciò significa che probabilmente dovrai scrivere più versioni del tuo codice sorgente C o C ++ per scegliere come target piattaforme diverse.

Ci sono altri problemi di cui preoccuparsi. Le specifiche C e C ++ sono deliberatamente vaghe per consentire agli implementatori di mirare a un'ampia varietà di hardware, dai mainframe ai microcontrollori. Le dimensioni dei tipi primitivi ( char , int , short , long , float , ecc.) Non sono corretti: gli standard impongono che supportino almeno un intervallo minimo, ma possono essere più larghi di quanto richiesto da questo intervallo.

Ad esempio, lo standard di linguaggio C impone che un int sia in grado di rappresentare almeno l'intervallo [-32767...32767] , il che significa che deve essere almeno 16 bit largo. Tuttavia, l'intento con int è che si associa alla dimensione nativa della parola, il che significa che sulla maggior parte dell'hardware costruito dal 1990, un int è largo 32 bit. Tuttavia, troverai oddball che usano ancora un int a 16 bit, e c'è almeno una vecchia piattaforma che utilizzava una parola a 36 bit, ma le probabilità sono che non la vedrai mai.

Per sicurezza, si dovrebbe presumere che gli intervalli minimi siano supportati per ogni tipo dato.

C non impone un endianness specifico: se stai facendo un pasticcio con la serializzazione / deserializzazione, dovrai considerare se la piattaforma è big o little-endian.

Questa è solo la parte della mia testa (molto intontita). C'è più di quanto non stia pensando.

TL / DR - tu potresti essere in grado di scrivere una singola versione del tuo codice sorgente C o C ++ e semplicemente compilarlo per ogni target differente, ma non ci conterei .

    
risposta data 30.03.2017 - 18:14
fonte
0

Sulla base delle applicazioni su cui ho lavorato e scritto in C / C ++ è possibile fare tra il 50% e il 90%.

Se si tratta di un'utilità da riga di comando o di un server, probabilmente si potrebbe raggiungere il 90%. Ovviamente, è necessario scegliere quale variante della lingua è necessario utilizzare. Ad esempio, se stai bersagliando una macchina orientata alla parola (Sperry e Burroughs ne hanno costruiti alcuni) che ha solo un compilatore K & RC, dovrai usare K & RC e usare le funzionalità compatibili con le versioni precedenti di ANSI C (cioè, usa K & Dichiarazioni e definizioni R e non fanno conversioni implicite nei segni). Generalmente gli standard più vecchi hanno un supporto migliore per più sistemi man mano che sono vecchi.

Per l'interfaccia utente, si sposterà verso il basso verso il 50%. Se si utilizza una libreria GUI multipiattaforma (WxWidgets o qt), dovrebbe spostarsi più vicino al 90%.

Quando inizi a considerare in quale direzione andare, prendi un codice di esempio e compilarlo nei vari sistemi per provare a vedere cosa funzionerà per te. Inoltre, esegui regolarmente test unitari su ciascun sistema mentre sviluppi il codice.

    
risposta data 30.03.2017 - 16:20
fonte

Leggi altre domande sui tag