Teknik untuk memastikan kompatibilitas lintas platform (C ++)?

13

Saya sedang menyelesaikan salah satu proyek C ++ saya yang paling awal (yang menurut kerangka kerja) adalah cross-platform. Saya mengembangkan proyek sepenuhnya di Windows dan Visual Studio, berpikir bahwa karena perpustakaan semua lintas-platform, maka melakukan pembangunan OSX "nanti" akan sepele. Ini ternyata tidak menjadi masalah, melainkan "kode Windows" tidak berjalan dengan baik dan memiliki beberapa kesalahan kompilasi yang harus diperbaiki.

Teknik apa yang ada sebelumnya memastikan bahwa kode tersebut kompatibel dengan semua platform? Mengembangkan semua platform secara bersamaan, sehingga menguji kode terhadap setiap platform pada saat yang sama, ketika fitur baru ditambahkan, daripada mengembangkan versi platform yang berbeda satu demi satu? (*)

Mencari saran khusus yang tidak tergantung pada alat, tetapi "proses pengembangan" yang membantu kompatibilitas lintas platform, terlepas dari alat apa yang digunakan. Seperti yang (*) di atas.


Khususnya saya sedang mengembangkan plug-in VST dengan WDL-OL ( https://github.com/olilarkin/wdl-ol ) dan beberapa perpustakaan DSP lintas-platform. Proyek WDL-OL memiliki proyek VS dan Xcode yang sudah diatur, tetapi saya kira masalahnya berasal dari perpustakaan dan kemudian perbedaan dalam kompiler.

mavavilj
sumber
1
tidak ada cara untuk memastikan portabilitas, hanya cara untuk meningkatkan / memaksimalkan portabilitas
phuclv
dan mengapa ini bukan duplikat? Saya percaya ada banyak pertanyaan serupa
phuclv
Apa yang sedang dilakukan aplikasi Anda? Bagaimana Anda menggunakannya? Pada baris perintah, atau melalui beberapa antarmuka grafis? Harap edit pertanyaan Anda untuk memperbaikinya.
Basile Starynkevitch
Dan kerangka apa yang Anda gunakan?
Basile Starynkevitch

Jawaban:

15

Membuat kode portabel bisa sangat menantang.

Pertama beberapa saran terkait bahasa yang jelas:

  • gunakan standar C ++ dan hindari perilaku yang tidak terdefinisi dengan hati-hati
  • terutama bergantung pada perpustakaan standar (dan perpustakaan portabel seperti boost )
  • selalu sertakan semua tajuk yang diharapkan. Jangan berasumsi bahwa Anda tidak memerlukan tajuk karena sudah termasuk dalam tajuk lain (yaitu pada satu implementasi spesifik !): Ini dapat menyebabkan kesalahan kompilasi
  • hindari konstruksi yang didukung oleh kompiler tetapi tidak dijamin oleh standar C ++ (mis. struct anonim atau array panjang variabel ): dapat menyebabkan kesalahan kompilasi.
  • gunakan opsi kompiler untuk membantu Anda menegakkan kepatuhan (menonaktifkan ekstensi spesifik kompiler, memaksimalkan tingkat pesan peringatan yang dikembalikan)
  • perlu diingat bahwa kode itu tidak cukup berfungsi: ada banyak jebakan portabilitas tergantung implementasi: ukuran tipe data (bahkan elementer), karakter yang dapat ditandatangani atau tidak ditandatangani secara default , asumsi tentang endianness , urutan evaluasi dalam ekspresi saat ini gunakan efek samping , dll.

Kemudian beberapa rekomendasi desain:

  • Memilih alternatif pustaka standar daripada fungsionalitas sistem operasi yang setara
  • Isolasi penggunaan dependensi sistem operasi sebanyak mungkin (misalnya, dalam fungsi pembungkus yang dikendalikan dengan kompilasi bersyarat)

Akhirnya poin-poin rumit:

  • pengkodean karakter: pada banyak sistem Anda dapat mengandalkan utf8 . Tetapi untuk Windows lebih rumit karena sistem mengharapkan ansi atau utf-16. Anda tentu saja dapat mengandalkan typedef (seperti TCHAR), tetapi ini kemudian dapat menjadi tantangan dalam kombinasi dengan pustaka standar (misalnya coutvs wcoutuntuk digunakan tergantung apakah menggunakan charatau wchar_t)
  • Jika untuk GUI / grafik / I / O tingkat lanjut Anda tidak dapat menemukan perpustakaan portabel yang sesuai dengan harapan / kebutuhan Anda, rancang arsitektur keseluruhan untuk mengisolasi komponen spesifik OS. Pembungkus mungkin tidak memadai di sini, karena banyaknya interaksi dan konsep yang terlibat.
  • Manfaatkan beberapa pola desain yang menarik seperti misalnya pabrik abstrak (ideal untuk merancang keluarga objek terkait seperti di UI khusus OS) atau mediator (ideal untuk mengimplementasikan kolaborasi antara keluarga objek terkait) dan menggunakannya bersama dengan kompilasi bersyarat .

Tapi ini hanya saran. Di area ini Anda tidak bisa mendapatkan kepastian.

Christophe
sumber
-Wall -Wextra -Werror
pipa
1
@pipe Anda juga harus -pedantic.
5gon12eder
@ 5gon12eder Poin yang sangat bagus dalam konteks jawaban ini.
pipa
11

Tidak ada yang dapat menjamin bahwa kode tersebut kompatibel dengan platform selain membangunnya, menjalankannya, dan mengujinya di sana. Oleh karena itu, pendekatan semua orang waras adalah membangun, menjalankan, dan menguji aplikasi mereka di setiap platform yang mereka proyeksikan perlu dibangun, dijalankan, dan diuji.

Continuous Integration (CI) dapat meringankan sedikit beban ini untuk proyek yang lebih kecil karena Anda bisa mendapatkan agen pembangun yang murah atau gratis untuk beberapa platform (kebanyakan Linux), melakukan pengembangan Anda pada Windows, dan cukup kembali ke Linux ketika ada masalah.

OSX CI cukup rumit.

DeadMG
sumber
Tidak disebutkan, apa CI?
mavavilj
5
Continuous Integration - pada dasarnya sekelompok server yang menjalankan build dan menguji untuk Anda.
DeadMG
@DeadMG Maksudmu seperti Mozilla Tinderbox?
Damian Yerrick
1
Travis CI menyediakan host build OSX gratis
Daenyth
Cukup gunakan Cmake.
raaj
9

Jika Anda meminta "proses pengembangan" dan platform pengembangan utama Anda adalah Windows dengan Visual Studio, maka saya akan menyarankan untuk mencoba membangun proyek Anda tanpa menyertakan "windows.h". Anda akan mendapatkan banyak kesalahan kompilasi yang akan mengarahkan Anda ke banyak tempat di mana Anda harus memperbaiki kode Anda. Misalnya, 'DWORD' tidak akan ditentukan # dan Anda harus menggantinya dengan uint32_tmana - mana (google for stdint.hdan Anda akan menemukan informasi yang berguna tentang tipe integer dan definisi lintas-platform mereka). Selanjutnya, Anda harus mengganti semua panggilan ke Win32 API, seperti,Sleep()dengan setara lintas platform mereka (sekali lagi, google adalah teman terbaik Anda, yang akan menunjukkan pertanyaan dan jawaban yang relevan di situs stack * .com). Anda mungkin tidak akan berhasil menemukan semua penggantian lintas platform yang relevan untuk kode Anda dan Anda harus mengembalikan include "windows."arahan Anda tetapi meletakkannya di bawah #ifdef _WIN32- lebih detail di sini

Terus ajukan lebih banyak pertanyaan konkret dan dapatkan jawaban - ini adalah saran umum untuk "apa yang seharusnya menjadi proses pengembangan"

EDIT 1 Saran saya yang lain adalah menggunakan gcc dan / atau dentang mesin pengembangan Windows Anda (bersama dengan Visual Studio)

mvidelgauz
sumber
3

Itu tergantung pada "beberapa kesalahan kompilasi" yang Anda sebutkan. Tanpa mengetahui siapa mereka, tidak mungkin untuk spesifik.

Saya punya kode lintas platform untuk Windows / Linux / iOS / Android / Mac. Setiap platform baru membawa beberapa kesalahan dan peringatan tambahan saat pertama kali ditambahkan. Anda akan dengan cepat mempelajari konstruksi mana yang menimbulkan masalah. Entah menghindari mereka, atau abstrak perbedaan menjadi header dengan #ifdefs. Cobalah untuk tidak pernah #ifdefantar platform dalam kode Anda sendiri.

Satu contoh:

void myfunction(MyClass &);
myfunction(MyClass());

membuat instance sementara MyClassyang dihapus setelah myfunctionkembali. Dengan beberapa kompiler C ++ saya, instance itu baca / tulis (dan fakta bahwa itu sementara dan akan segera dihancurkan tidak khawatir dengan kompiler). Dengan yang lain, myfunctionharus didefinisikan ulang untuk mengambil const MyClass &, atau kompilator mengeluh. Tidak masalah apa kata standar C ++, atau kompiler mana yang benar dan mana yang salah. Setelah menemukan kesalahan beberapa kali saya tahu (a) menyatakan variabel sementara jenis MyClassdan meneruskannya ke myfunctionatau (b) mendeklarasikan referensi constdi myfunctiondan gunakan mutabledi sana-sini untuk mendekonstasikan.

Intinya: menumpuk pengalaman dan mengembangkan standar pengkodean Anda sendiri.

Martin Kochanski
sumber
2
Itu adalah fitur yang salah dari MSVC. Jika poin Anda adalah bahwa pengembangan pada 1 sistem memungkinkan untuk merayap masuk, poin diambil. Tetapi hal spesifik itu bukanlah sesuatu yang harus Anda lakukan.
JDługosz
1
Satu hal yang baik dari menggunakan banyak rantai alat adalah bahwa subset umum yang mereka terima lebih cenderung benar, C ++ yang sesuai standar daripada apa yang masing-masing terima secara individual. Dalam kasus Anda, kode yang ditunjukkan jelas salah oleh standar dan kedua perbaikan yang Anda sebutkan adalah alternatif yang valid. Saya akan mengatakan apa pun yang dikatakan standar.
5gon12eder
1
Atau saya akan mengatakan cross-platform C ++ lebih membatasi daripada apa yang dikatakan standar. Dengan kata lain, bahkan jika standar mengatakan demikian, Anda masih tunduk pada penyebut umum terendah (atau, paling tidak kemampuan vendor) untuk platform yang harus Anda dukung. Ada banyak perpustakaan open-source yang harus mengecualikan katakanlah C ++ 11 karena sebagian kecil dari konstituen mereka (seperti pada warga negara) tidak mampu C ++ 11.
rwong
3

Cara yang mungkin untuk membantu portabilitas bisa dengan hanya mengandalkan deklarasi dan fitur yang disediakan oleh standar C ++ 11 , dan dengan menggunakan pustaka dan kerangka kerja lintas platform seperti POCO & Qt .

Tetapi bahkan ini bukan bukti kegagalan. Ingatlah pepatah itu

tidak ada yang namanya program portabel, hanya ada program yang telah berhasil porting (ke beberapa platform tertentu)

Dengan latihan, disiplin dan banyak pengalaman, memindahkan program ke platform lain biasanya dapat dilakukan dengan cepat. Tetapi pengalaman dan pengetahuan sangat penting.

Basile Starynkevitch
sumber
1
Saran lain adalah bahwa, ketika porting dilakukan oleh orang dan tim yang berbeda, bahwa perubahan kode harus diintegrasikan kembali ke jalur utama. Jika tidak, perbedaan platform menjadi pengetahuan yang ditimbun oleh tim yang melakukannya.
rwong