Kỹ thuật đảm bảo khả năng tương thích đa nền tảng (C ++)?


13

Tôi đã hoàn thành một trong những dự án C ++ đầu tiên của mình (theo khung) được cho là đa nền tảng. Tôi đã phát triển dự án đầy đủ trong Windows và Visual Studio, nghĩ rằng các thư viện đều là nền tảng chéo, nên việc xây dựng OSX "sau này" sẽ không đáng kể. Điều này hóa ra không phải là trường hợp, mà là "mã Windows" không chạy đúng và có một số lỗi biên dịch được sửa.

Những kỹ thuật tồn tại trước đó đảm bảo rằng mã tương thích với tất cả các nền tảng? Phát triển đồng thời tất cả các nền tảng, do đó kiểm tra mã dựa trên mọi nền tảng cùng một lúc, khi các tính năng mới được thêm vào, thay vì phát triển các phiên bản nền tảng khác nhau lần lượt? (*)

Nhìn cụ thể khuyên rằng điều đó không phụ thuộc vào các công cụ, mà là "các quy trình phát triển" giúp tương thích đa nền tảng, bất kể công cụ nào được sử dụng. Giống như một (*) ở trên.


Cụ thể, tôi đang phát triển trình cắm VST với WDL-OL ( https://github.com/olilarkin/wdl-ol ) và một số thư viện DSP đa nền tảng. Các dự án WDL-OL có cả dự án VS và Xcode được thiết lập, nhưng tôi đoán các vấn đề đến từ các thư viện và sau đó là sự khác biệt trong trình biên dịch.


1
không có cách nào để đảm bảo tính di động, chỉ có cách cải thiện / tối đa hóa tính di động
phuclv

và tại sao đây không phải là một bản sao? Tôi tin rằng có rất nhiều câu hỏi tương tự
phuclv

Ứng dụng của bạn đang làm gì? Làm thế nào bạn sẽ sử dụng nó? Trên dòng lệnh, hoặc thông qua một số giao diện đồ họa? Vui lòng chỉnh sửa câu hỏi của bạn để cải thiện nó.
Basile Starynkevitch

Và bạn đang sử dụng khuôn khổ nào?
Basile Starynkevitch

Câu trả lời:


15

Tạo mã di động có thể rất khó khăn.

Đầu tiên một số lời khuyên liên quan đến ngôn ngữ rõ ràng:

  • sử dụng C ++ tiêu chuẩn và tránh cẩn thận mọi hành vi không xác định
  • chủ yếu dựa vào thư viện chuẩn (và thư viện di động như boost )
  • luôn luôn bao gồm tất cả các tiêu đề dự kiến. Đừng cho rằng bạn không cần một tiêu đề vì nó được bao gồm trong một tiêu đề khác (nghĩa là trên một triển khai cụ thể !): Điều này có thể gây ra lỗi biên dịch
  • tránh các cấu trúc được hỗ trợ bởi trình biên dịch nhưng không được đảm bảo bởi tiêu chuẩn C ++ (ví dụ: cấu trúc ẩn danh hoặc mảng có chiều dài thay đổi ): có thể gây ra lỗi biên dịch.
  • sử dụng các tùy chọn trình biên dịch để giúp bạn thực thi tuân thủ (vô hiệu hóa các tiện ích mở rộng cụ thể của trình biên dịch, tối đa hóa mức độ thông báo cảnh báo được trả về)
  • Hãy nhớ rằng mã không hoạt động: có nhiều cạm bẫy về tính di động phụ thuộc khi thực hiện: kích thước của các loại dữ liệu (thậm chí là cơ bản), các ký tự có thể được ký hoặc không dấu theo mặc định , các giả định về tính xác thực , thứ tự đánh giá trong các biểu thức khi chúng sử dụng tác dụng phụ , vv

Sau đó, một vài khuyến nghị thiết kế:

  • Thích thư viện tiêu chuẩn thay thế cho chức năng hệ điều hành tương đương
  • Cô lập việc sử dụng các phụ thuộc hệ điều hành càng nhiều càng tốt (ví dụ, trong một hàm bao bọc được kiểm soát với quá trình biên dịch có điều kiện)

Cuối cùng là những điểm tinh tế:

  • mã hóa ký tự: trên nhiều hệ thống bạn có thể dựa vào utf8 . Nhưng đối với Windows, nó tinh tế hơn khi hệ thống mong đợi ansi hoặc utf-16. Tất nhiên bạn có thể dựa vào một typedef (như TCHAR), nhưng điều này sau đó có thể là thử thách kết hợp với thư viện chuẩn (ví dụ: coutvs wcoutđược sử dụng tùy thuộc vào việc sử dụng charhoặc wchar_t)
  • Nếu đối với GUI / đồ họa / I / O nâng cao, bạn không thể tìm thấy thư viện di động phù hợp với mong muốn / yêu cầu của mình, hãy thiết kế kiến ​​trúc tổng thể để tách biệt các thành phần dành riêng cho hệ điều hành. Wrappers có thể không đủ ở đây, do có nhiều tương tác và khái niệm khác nhau liên quan.
  • Tận dụng một số mẫu thiết kế thú vị, chẳng hạn như nhà máy trừu tượng (lý tưởng để thiết kế các họ của các đối tượng liên quan như trong UI cụ thể của hệ điều hành) hoặc hòa giải (lý tưởng để thực hiện sự hợp tác giữa các gia đình của các đối tượng liên quan) và sử dụng chúng cùng với việc biên dịch có điều kiện .

Nhưng đây chỉ là những lời khuyên. Trong lĩnh vực này, bạn không thể đạt được sự chắc chắn.


-Wall -Wextra -Werror
đường ống

1
@pipe Bạn cũng nên như vậy -pedantic.
5gon12eder

@ 5gon12eder Một điểm rất hay trong ngữ cảnh của câu trả lời này.
ống

11

Không có gì có thể đảm bảo rằng mã tương thích với một nền tảng khác ngoài việc xây dựng nó, chạy nó và thử nghiệm nó ở đó. Do đó, cách tiếp cận của tất cả mọi người lành mạnh là xây dựng, chạy và kiểm tra ứng dụng của họ trên mọi nền tảng mà họ dự kiến ​​sẽ cần phải được xây dựng, chạy và thử nghiệm.

Tích hợp liên tục (CI) có thể giảm bớt gánh nặng này một chút công bằng cho các dự án nhỏ hơn vì bạn có thể nhận các tác nhân xây dựng giá rẻ hoặc miễn phí cho một số nền tảng (chủ yếu là Linux), phát triển trên Windows và chỉ cần quay lại Linux khi có sự cố.

OSX CI là khá khó khăn mặc dù.


Không có đề cập, CI là gì?
mavavilj

5
Tích hợp liên tục - về cơ bản là một loạt các máy chủ chạy các bản dựng và kiểm tra cho bạn.
DeadMG

@DeadMG Ý bạn là như Mozilla Tinderbox?
Damian Yerrick

1
Travis CI cung cấp máy chủ xây dựng OSX miễn phí
Daenyth

Chỉ cần sử dụng Cmake.
raaj

9

Nếu bạn đang yêu cầu "quy trình phát triển" và nền tảng phát triển chính của bạn là Windows với Visual Studio thì tôi khuyên bạn nên thử xây dựng dự án của mình mà không có "windows.h". Bạn sẽ nhận được rất nhiều lỗi biên dịch sẽ đưa bạn đến nhiều nơi mà bạn sẽ cần cấu trúc lại mã của mình. Ví dụ: 'DWORD' sẽ không được #d xác định và bạn sẽ cần thay thế nó uint32_tở mọi nơi (google cho stdint.hvà bạn sẽ tìm thấy thông tin hữu ích về các loại số nguyên và định nghĩa đa nền tảng của chúng). Tiếp theo, bạn sẽ cần thay thế tất cả các cuộc gọi đến API Win32, chẳng hạn như,Sleep()với tương đương đa nền tảng của họ (một lần nữa, google là người bạn tốt nhất của bạn, người sẽ hiển thị các câu hỏi và câu trả lời có liên quan trong các trang web stack * .com). Bạn có thể sẽ không thành công khi tìm thấy tất cả các thay thế đa nền tảng có liên quan cho mã của mình và bạn sẽ phải trả lại include "windows."chỉ thị của mình nhưng đặt nó bên dưới #ifdef _WIN32- chi tiết hơn tại đây

Tiếp tục đặt câu hỏi cụ thể hơn và nhận câu trả lời - đây là gợi ý chung cho "quá trình phát triển nên là gì"

EDIT 1 Một đề nghị khác của tôi là sử dụng gcc và / hoặc clang trên máy phát triển Windows của bạn (cùng với Visual Studio)


3

Nó phụ thuộc vào "một số lỗi biên dịch" mà bạn đề cập. Không biết chúng là gì, không thể cụ thể được.

Tôi đã có mã đa nền tảng cho Windows / Linux / iOS / Android / Mac. Mỗi nền tảng mới mang lại một số lỗi và cảnh báo bổ sung khi lần đầu tiên được thêm vào. Bạn sẽ nhanh chóng tìm hiểu các cấu trúc mang lại vấn đề. Hoặc tránh chúng, hoặc trừu tượng hóa sự khác biệt thành một tiêu đề với #ifdefs. Cố gắng không bao giờ#ifdef giữa các nền tảng trong chính mã của bạn.

Một ví dụ:

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

tạo một thể hiện tạm thời MyClassbị xóa sau khi myfunctiontrả về. Với một số trình biên dịch C ++ của tôi, trường hợp đó là đọc / ghi (và thực tế là nó tạm thời và sẽ sớm bị hủy không khiến trình biên dịch lo lắng). Với những người khác, myfunctionphải được xác định lại để lấy const MyClass &, hoặc trình biên dịch phàn nàn. Không quan trọng tiêu chuẩn C ++ nói gì, hoặc trình biên dịch nào đúng và sai. Sau khi gặp lỗi một vài lần, tôi biết (a) hoặc khai báo một biến tạm thời của loại MyClassvà chuyển nó sang myfunctionhoặc (b) khai báo tham chiếu consttrong myfunctionvà sử dụngmutable ở đây và ở đó để giải mã.

Điểm mấu chốt: tích lũy kinh nghiệm và phát triển các tiêu chuẩn mã hóa của riêng bạn.


2
Đó là một tính năng sai của MSVC. Nếu quan điểm của bạn là phát triển trên 1 hệ thống cho phép những thứ này leo vào, lấy điểm. Nhưng điều cụ thể đó không phải là điều bạn nên làm.
JDługosz

1
Một điều tốt khi sử dụng nhiều chuỗi công cụ là tập hợp con chung mà họ chấp nhận có nhiều khả năng là chính xác, tuân thủ tiêu chuẩn C ++ so với những gì mỗi nhóm chấp nhận riêng lẻ. Trong trường hợp của bạn, mã hiển thị rõ ràng là sai theo tiêu chuẩn và cả hai bản sửa lỗi được đề cập của bạn là các lựa chọn thay thế hợp lệ. Tôi muốn nói nó không quan trọng những gì tiêu chuẩn nói.
5gon12eder

1
Hoặc tôi sẽ nói C ++ đa nền tảng hạn chế hơn những gì tiêu chuẩn nói. Nói cách khác, ngay cả khi tiêu chuẩn nói như vậy, bạn vẫn phải tuân theo mẫu số chung thấp nhất (hoặc, khả năng của nhà cung cấp ít nhất) cho các nền tảng mà bạn phải hỗ trợ. Có rất nhiều thư viện mã nguồn mở phải loại trừ C ++ 11 vì một phần nhỏ các thành phần của chúng (như trong công dân) không có khả năng C ++ 11.
rwong

3

Một cách khả thi để giúp tính di động có thể chỉ dựa vào các khai báo và các tính năng được cung cấp bởi tiêu chuẩn C ++ 11 và bằng cách sử dụng các thư viện và khung đa nền tảng như POCO & Qt .

Nhưng ngay cả điều này không phải là bằng chứng thất bại. Ghi nhớ câu cách ngôn

không có thứ gọi là chương trình di động, chỉ có những chương trình đã được chuyển thành công (sang một số nền tảng cụ thể)

Với thực hành, kỷ luật và rất nhiều kinh nghiệm, việc chuyển một chương trình sang nền tảng khác thường có thể được thực hiện nhanh chóng. Nhưng kinh nghiệm và bí quyết rất nhiều vấn đề.


1
Một lời khuyên khác là, khi việc chuyển mạng được thực hiện bởi những người và nhóm khác nhau, các thay đổi mã phải được tích hợp lại vào dòng chính. Mặt khác, sự khác biệt về nền tảng trở thành một kiến ​​thức được tích trữ bởi nhóm đã làm điều đó.
rwong
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.