เทคนิคในการตรวจสอบความเข้ากันได้ข้ามแพลตฟอร์ม (C ++)?


13

ฉันเสร็จหนึ่งในโครงการ C ++ ที่เร็วที่สุดซึ่งก็คือ (ตามกรอบ) ที่ควรจะเป็นข้ามแพลตฟอร์ม ฉันพัฒนาโครงการอย่างสมบูรณ์ใน Windows และ Visual Studio โดยคิดว่าเนื่องจากห้องสมุดเป็นแพลตฟอร์มข้ามแพลตฟอร์มทั้งหมดดังนั้นการทำ OSX build "ในภายหลัง" จึงเป็นเรื่องเล็กน้อย สิ่งนี้กลับกลายเป็นว่าไม่ใช่กรณี แต่ "รหัส Windows" ทำงานไม่ถูกต้องและมีข้อผิดพลาดในการรวบรวมเพื่อแก้ไข

เทคนิคใดที่มีอยู่ก่อนเพื่อให้แน่ใจว่ารหัสเข้ากันได้กับทุกแพลตฟอร์ม? การพัฒนาแพลตฟอร์มทั้งหมดพร้อมกันดังนั้นจึงทดสอบโค้ดกับทุกแพลตฟอร์มในเวลาเดียวกันเมื่อมีการเพิ่มฟีเจอร์ใหม่แทนที่จะพัฒนาแพลทฟอร์มรุ่นที่แตกต่างกันหลังจากนั้นหรือไม่ (*)

มองหาคำแนะนำเฉพาะที่ไม่ได้ขึ้นอยู่กับเครื่องมือ แต่เป็น "กระบวนการพัฒนา" ที่ช่วยให้สามารถทำงานร่วมกันได้ข้ามแพลตฟอร์มโดยไม่คำนึงถึงเครื่องมือที่ใช้ เช่นเดียวกับ (*) ด้านบน


โดยเฉพาะฉันกำลังพัฒนาปลั๊กอิน VST ด้วย WDL-OL ( https://github.com/olilarkin/wdl-ol ) และห้องสมุด DSP ข้ามแพลตฟอร์ม โครงการ WDL-OL มีทั้งโครงการ VS และ Xcode ตั้งค่า แต่ฉันเดาว่าปัญหามาจากไลบรารีและจากนั้นความแตกต่างในคอมไพเลอร์


1
ไม่มีวิธีที่จะประกันความสะดวกในการพกพามีเพียงวิธีในการปรับปรุง / เพิ่มความสะดวกในการพกพาให้มากที่สุด
phuclv

และทำไมนี่ไม่ซ้ำกัน? ฉันเชื่อว่ามีคำถามที่คล้ายกันจำนวนมาก
phuclv

แอปพลิเคชันของคุณกำลังทำอะไรอยู่ คุณจะใช้มันอย่างไร? ในบรรทัดคำสั่งหรือผ่านส่วนต่อประสานแบบกราฟิกบางส่วน โปรดแก้ไขคำถามของคุณเพื่อปรับปรุง
Basile Starynkevitch

และคุณใช้กรอบอะไร
Basile Starynkevitch

คำตอบ:


15

การสร้างรหัสพกพานั้นเป็นเรื่องที่ท้าทายมาก

ก่อนอื่นคำแนะนำที่เกี่ยวข้องกับภาษาที่ชัดเจน:

  • ใช้ C ++ มาตรฐานและหลีกเลี่ยงพฤติกรรมที่ไม่ได้กำหนดอย่างระมัดระวัง
  • พึ่งพาไลบรารีมาตรฐาน (และไลบรารีแบบพกพาเช่นการเพิ่ม )
  • รวมส่วนหัวที่คาดหวังไว้เสมอ อย่าคิดว่าคุณไม่จำเป็นต้องมีส่วนหัวเพราะมันรวมอยู่ในอีกอันหนึ่ง (เช่นในการนำไปใช้ที่เฉพาะเจาะจง !): สิ่งนี้อาจทำให้เกิดข้อผิดพลาดในการรวบรวม
  • หลีกเลี่ยงการสร้างที่รองรับโดยคอมไพเลอร์ แต่ไม่รับประกันตามมาตรฐานC ++ (เช่นโครงสร้างที่ไม่ระบุชื่อหรืออาร์เรย์ความยาวผันแปร ): อาจทำให้เกิดข้อผิดพลาดในการคอมไพล์
  • ใช้ตัวเลือกคอมไพเลอร์เพื่อช่วยให้คุณบังคับใช้การปฏิบัติตามข้อกำหนด (ปิดใช้งานส่วนขยายเฉพาะคอมไพเลอร์เพิ่มระดับของข้อความเตือนที่ส่งคืน)
  • เก็บไว้ในใจว่ามันไม่เพียงพอว่ารหัสการทำงาน: มีหลายการดำเนินการผิดพลาดในการพกพาขึ้นอยู่กับขนาดของ (แม้ประถม) ชนิดข้อมูลตัวละครที่สามารถลงนามหรือไม่มีการลงชื่อโดยค่าเริ่มต้นสมมติฐานเกี่ยวกับendiannessคำสั่งของการประเมินผลในการแสดงออกเมื่อเหล่านี้ ใช้ผลข้างเคียงฯลฯ

จากนั้นคำแนะนำการออกแบบสองสามข้อ:

  • ต้องการไลบรารีมาตรฐานแทนการทำงานของระบบปฏิบัติการที่เทียบเท่า
  • แยกการใช้การพึ่งพาระบบปฏิบัติการให้มากที่สุดเท่าที่จะทำได้ (ตัวอย่างเช่นในฟังก์ชันตัวตัดคำที่ควบคุมด้วยการคอมไพล์แบบมีเงื่อนไข)

ในที่สุดจุดที่ละเอียดอ่อน:

  • การเข้ารหัสอักขระ: ในหลาย ๆ ระบบคุณสามารถเชื่อถือได้บนutf8 แต่สำหรับ Windows มันมีความละเอียดอ่อนมากกว่าเนื่องจากระบบคาดหวังว่า ansi หรือ utf-16 แน่นอนว่าคุณสามารถพึ่งพา typedef (เช่นTCHAR) แต่สิ่งนี้อาจท้าทายเมื่อใช้ร่วมกับไลบรารีมาตรฐาน (เช่นcoutvs wcoutเพื่อใช้ขึ้นอยู่กับการใช้งานcharหรือwchar_t)
  • ถ้าสำหรับ GUI / graphics / I / O ขั้นสูงคุณไม่สามารถหาไลบรารี่แบบพกพาที่ตรงกับความต้องการ / ความต้องการของคุณได้ให้ออกแบบสถาปัตยกรรมโดยรวมเพื่อแยกส่วนประกอบเฉพาะของระบบปฏิบัติการ แรปเปอร์อาจไม่เพียงพอที่นี่เนื่องจากมีปฏิสัมพันธ์และแนวคิดต่าง ๆ มากมายที่เกี่ยวข้อง
  • ใช้ประโยชน์จากรูปแบบการออกแบบที่น่าสนใจบางอย่างเช่นโรงงานนามธรรม (เหมาะสำหรับการออกแบบตระกูลของวัตถุที่เกี่ยวข้องเช่นใน OS เฉพาะ UI) หรือผู้ไกล่เกลี่ย (เหมาะที่จะใช้การทำงานร่วมกันระหว่างครอบครัวของวัตถุที่เกี่ยวข้อง) และใช้ร่วมกับการรวบรวมเงื่อนไข .

แต่นี่เป็นเพียงคำแนะนำเท่านั้น ในบริเวณนี้คุณไม่สามารถมั่นใจได้


-Wall -Wextra -Werror
ท่อ

1
@pipe คุณควรจะเป็น-pedanticเช่นนั้น
5gon12eder

@ 5gon12eder จุดที่ดีมากในบริบทของคำตอบนี้
ท่อ

11

ไม่มีสิ่งใดที่สามารถรับประกันได้ว่ารหัสนั้นเข้ากันได้กับแพลตฟอร์มอื่น ๆ นอกเหนือจากการสร้างรันและทดสอบที่นั่น ดังนั้นวิธีการของคนมีเหตุผลทั้งหมดคือการสร้างเรียกใช้และทดสอบแอปพลิเคชันของพวกเขาในทุกแพลตฟอร์มที่พวกเขาคาดการณ์ว่าจะต้องมีการสร้างรันและทดสอบ

การรวมอย่างต่อเนื่อง (CI) สามารถลดภาระนี้ให้เป็นธรรมสำหรับโครงการขนาดเล็กเนื่องจากคุณสามารถรับตัวแทนสร้างราคาถูกหรือฟรีสำหรับบางแพลตฟอร์ม (ส่วนใหญ่เป็น Linux) ทำการพัฒนาบน Windows และกลับไปที่ Linux เมื่อมีปัญหา

OSX CI นั้นค่อนข้างยุ่งยาก


ไม่มีการเอ่ยถึง CI คืออะไร
mavavilj

5
การรวมอย่างต่อเนื่อง - โดยทั่วไปเป็นเซิร์ฟเวอร์จำนวนมากที่รันการสร้างและทดสอบสำหรับคุณ
DeadMG

@DeadMG คุณหมายถึง Mozilla Tinderbox ใช่ไหม
Damian Yerrick

1
Travis CI ให้บริการโฮสต์สำหรับการสร้าง OSX ฟรี
Daenyth

เพียงใช้ Cmake
raaj

9

หากคุณกำลังขอ "กระบวนการพัฒนา" และแพลตฟอร์มการพัฒนาหลักของคุณคือ Windows ที่มี Visual Studio ฉันขอแนะนำให้ลองสร้างโครงการของคุณโดยไม่มี "windows.h" รวมอยู่ด้วย คุณจะได้รับข้อผิดพลาดในการรวบรวมจำนวนมากซึ่งจะนำคุณไปยังที่ต่างๆที่คุณจะต้องทำการปรับรหัสให้ใหม่ ตัวอย่างเช่น 'DWORD' จะไม่ #defined และคุณจะต้องแทนที่ด้วยuint32_tทุกที่ (google for stdint.hและคุณจะพบข้อมูลที่เป็นประโยชน์เกี่ยวกับประเภทจำนวนเต็มและคำจำกัดความข้ามแพลตฟอร์มของพวกเขา) ถัดไปคุณจะต้องแทนที่การเรียกไปยัง Win32 API ทั้งหมดเช่นSleep()ด้วยการทำงานข้ามแพลตฟอร์มของพวกเขา (อีกครั้ง google เป็นเพื่อนที่ดีที่สุดของคุณซึ่งจะแสดงคำถามและคำตอบที่เกี่ยวข้องในไซต์ stack * .com) คุณอาจจะไม่ประสบความสำเร็จในการค้นหาการแทนที่ข้ามแพลตฟอร์มที่เกี่ยวข้องทั้งหมดสำหรับรหัสของคุณและคุณจะต้องส่งคืนinclude "windows."คำสั่งของคุณแต่วางไว้ใต้#ifdef _WIN32- รายละเอียดเพิ่มเติมที่นี่

ถามคำถามที่เป็นรูปธรรมมากขึ้นและรับคำตอบ - นี่คือคำแนะนำทั่วไปสำหรับ "สิ่งที่ควรเป็นกระบวนการพัฒนา"

แก้ไข 1 อีกข้อเสนอแนะของฉันคือการใช้ gcc และ / หรือเสียงดังกราวบนเครื่องพัฒนา Windows ของคุณ (พร้อมกับ Visual Studio)


3

ขึ้นอยู่กับ "ข้อผิดพลาดในการรวบรวม" ที่คุณพูดถึง โดยไม่ทราบว่ามันคืออะไรมันเป็นไปไม่ได้ที่จะเจาะจง

ฉันมีรหัสข้ามแพลตฟอร์มสำหรับ Windows / Linux / iOS / Android / Mac แพลตฟอร์มใหม่แต่ละแห่งมีข้อผิดพลาดและคำเตือนเพิ่มเติมเมื่อมีการเพิ่มครั้งแรก คุณจะได้เรียนรู้อย่างรวดเร็วว่าโครงสร้างใดที่ทำให้เกิดปัญหา หลีกเลี่ยงพวกเขาหรือสรุปความแตกต่างในส่วนหัวด้วย#ifdefs ลองไม่เคย#ifdefระหว่างแพลตฟอร์มภายในรหัสของคุณเอง

ตัวอย่างหนึ่ง:

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

สร้างอินสแตนซ์ชั่วคราวMyClassซึ่งจะถูกลบหลังจากmyfunctionส่งคืนแล้ว ด้วยคอมไพเลอร์ C ++ บางตัวของฉันอินสแตนซ์นั้นก็คืออ่าน / เขียน (และความจริงที่ว่ามันเป็นชั่วคราวและในไม่ช้าจะถูกทำลายไม่ต้องกังวลกับคอมไพเลอร์) กับผู้อื่นmyfunctionจะต้องมีการนิยามใหม่ให้ใช้const MyClass &หรือคอมไพเลอร์บ่น ไม่สำคัญว่ามาตรฐาน C ++ จะพูดว่าอะไรหรือคอมไพเลอร์ใดถูกต้องและผิด หลังจากพบข้อผิดพลาดสองสามครั้งผมรู้ว่า (ก) ทั้งประกาศตัวแปรชั่วคราวของประเภทMyClassและผ่านที่myfunctionหรือ (ข) ประกาศอ้างอิงconstในmyfunctionและใช้mutableนี่และมีการ deconstify

Bottom line: สะสมประสบการณ์และพัฒนามาตรฐานการเข้ารหัสของคุณเอง


2
นั่นเป็นคุณสมบัติที่ผิดพลาดของ MSVC หากประเด็นของคุณคือการพัฒนาระบบ 1 ช่วยให้สิ่งเหล่านี้สามารถคืบคลานได้ แต่สิ่งนั้นไม่ใช่สิ่งที่คุณควรทำ
JDługosz

1
สิ่งหนึ่งที่ดีในการใช้เครื่องมือหลาย ๆ โซ่คือชุดย่อยทั่วไปที่พวกเขายอมรับนั้นมีแนวโน้มที่จะถูกต้องตามมาตรฐาน C ++ มากกว่าสิ่งที่แต่ละคนยอมรับเป็นรายบุคคล ในกรณีของคุณรหัสที่แสดงนั้นผิดอย่างชัดเจนโดยมาตรฐานและการแก้ไขที่คุณระบุทั้งสองเป็นทางเลือกที่ถูกต้อง ฉันว่ามันไม่สำคัญว่ามาตรฐานจะพูดว่าอย่างไร
5gon12eder

1
หรือฉันจะบอกว่าข้ามแพลตฟอร์ม C ++ นั้นเข้มงวดกว่าที่มาตรฐานบอกไว้ กล่าวอีกนัยหนึ่งถึงแม้ว่ามาตรฐานจะบอกว่าคุณยังคงอยู่ภายใต้ตัวหารร่วมที่ต่ำที่สุด (หรือความสามารถขั้นต่ำของผู้ขาย) สำหรับแพลตฟอร์มที่คุณต้องให้การสนับสนุน มีโอเพ่นซอร์สไลบรารีมากมายที่ต้องแยกออกว่า C ++ 11 เพราะส่วนหนึ่งขององค์ประกอบ (ในฐานะพลเมือง) ไม่สามารถใช้ C ++ 11 ได้
ร. ว.

3

วิธีที่เป็นไปได้เพื่อช่วยเหลือพกพาอาจจะต้องพึ่งพาเพียงในการประกาศและคุณลักษณะให้โดยC ++ 11มาตรฐานและโดยการใช้ไลบรารีข้ามแพลตฟอร์มและกรอบเหมือนPOCOและQt

แต่นี่ไม่ใช่ข้อพิสูจน์ จำคำพังเพย

ไม่มีสิ่งดังกล่าวเป็นโปรแกรมพกพามีเพียงโปรแกรมที่ได้รับการพอร์ตเรียบร้อยแล้ว (ไปยังแพลตฟอร์มบางอย่าง)

ด้วยการฝึกฝนวินัยและมากประสบการณ์, porting โปรแกรมเพื่อแพลตฟอร์มอื่นสามารถมักจะทำได้อย่างรวดเร็ว แต่ประสบการณ์และความรู้มีความสำคัญมาก


1
คำแนะนำอีกประการหนึ่งคือเมื่อการย้ายระบบกระทำโดยบุคคลและทีมที่แตกต่างกันการเปลี่ยนรหัสจะต้องรวมเข้ากับการฉีดอีกครั้ง มิฉะนั้นความแตกต่างของแพลตฟอร์มจะกลายเป็นความรู้ที่สะสมโดยทีมที่ทำมัน
ร. ว.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.