确保跨平台兼容性(C ++)的技术?


13

我正在完成我最早的C ++项目之一(根据框架),该项目应该是跨平台的。我完全在Windows和Visual Studio中开发了该项目,以为既然这些库都是跨平台的,那么“以后”进行OSX构建将是微不足道的。事实并非如此,而是“ Windows代码”无法正常运行,并且需要解决一些编译错误。

预先存在哪些技术可以确保代码与所有平台兼容?同时开发所有平台,从而在添加新功能时针对每个平台同时测试代码,而不是一个接一个地开发不同的平台版本?(*)

从外观上来看,特别建议不要依赖于工具,而可以使用“开发过程”来帮助跨平台兼容性,无论使用什么工具。就像上面的一个(*)。


具体来说,我正在使用WDL-OL(https://github.com/olilarkin/wdl-ol)和一些跨平台DSP库开发VST插件。WDL-OL项目同时设置了VS和Xcode项目,但我想问题出在库中,然后是编译器之间的差异。


1
没有办法确保便携性,只有提高/最大化便携性的方法
phuclv

为什么这不是重复的?我相信会有很多类似的问题
phuclv

您的应用程序在做什么?您将如何使用它?在命令行上还是通过某些图形界面?请修改您的问题以进行改进。
Basile Starynkevitch

您正在使用什么框架?
Basile Starynkevitch

Answers:


15

创建可移植代码可能非常具有挑战性。

首先是一些明显的语言相关建议:

  • 使用标准C ++,并小心避免任何未定义的行为
  • 主要依赖于标准库(以及可移植库,例如boost
  • 始终包含所有预期的标题。不要假设您不需要标头,因为它包含在另一个标头中(即在一个特定的实现中!):这可能会导致编译错误
  • 避免使用编译器支持但C ++标准不能保证的结构(例如,匿名结构可变长度数组):可能导致编译错误。
  • 使用编译器选项来帮助您强制合规(禁用编译器特定的扩展,最大程度地返回警告消息)
  • 请记住,代码能否正常工作还不够:实现依赖于可移植性存在许多陷阱:(甚至是基本)数据类型的大小,默认情况下可以带符号或无符号的字符,有关字节序的假设,表达式中的求值顺序使用副作用

然后是一些设计建议:

  • 首选标准库替代等效的操作系统功能
  • 尽可能隔离使用操作系统依赖项(例如,在有条件编译控制的包装器函数中)

最后的微妙之处是:

  • 字符编码:在许多系统上,您都可以依赖utf8。但是对于Windows,由于系统希望使用ansi或utf-16,因此更加精致。您当然可以依赖typedef(如TCHAR),但是与标准库结合使用时可能会遇到挑战(例如,要使用coutvs wcout取决于使用char还是wchar_t
  • 如果对于GUI /图形/高级I / O,您找不到适合您期望/要求的可移植库,请设计总体体系结构以隔离特定于OS的组件。由于涉及许多不同的交互作用和概念,因此在这里包装可能并不足够。
  • 充分利用一些有趣的设计模式,例如抽象工厂(理想的用于设计相关对象的族,例如在OS特定的UI中)或中介程序(理想的实现相关对象族之间的协作),并将它们与条件编译一起使用。

但这只是建议。在这方面,您无法确定。


-Wall -Wextra -Werror
管道

1
@pipe你也应该是-pedantic
5gon12eder 2016年

@ 5gon12eder在此答案的上下文中的一个很好的观点。

11

除了在平台上构建,运行和测试之外,没有什么可以保证代码与平台兼容。因此,所有有理智的人的方法是在他们需要构建,运行和测试的每个平台上构建,运行和测试他们的应用程序。

连续集成(CI)可以减轻较小项目的负担,因为您可以获得某些平台(主要是Linux)的廉价或免费构建代理,可以在Windows上进行开发,并在出现问题时仅返回Linux。

OSX CI非常棘手。


没有提及,什么是CI?
mavavilj

5
持续集成-基本上是一堆为您运行构建和测试的服务器。
DeadMG '16

@DeadMG您的意思是像Mozilla Tinderbox一样?
Damian Yerrick '16

1
Travis CI提供免费的OSX构建主机
Daenyth,2016年

只需使用Cmake。
raaj

9

如果您要求“开发过程”,而您的主要开发平台是带有Visual Studio的Windows,则建议您尝试构建不包含“ windows.h”的项目。您会遇到很多编译错误,这些错误会指向许多需要重构代码的地方。例如,不会对#DWORD进行#defined定义,而需要在uint32_t任何地方都将其替换(google for stdint.h,您将找到有关整数类型及其跨平台定义的有用信息)。接下来,您将需要替换所有对Win32 API的调用,例如,Sleep()以及与之等效的跨平台(同样,google是您最好的朋友,他会在stack * .com网站上显示相关的问题和答案)。你可能不会成功找到所有相关的跨平台替代你的代码,你就必须回到你的include "windows."指令,但把它放在#ifdef _WIN32-更多详情点击这里

不断提出更具体的问题并获得答案-这是“开发过程应该是什么”的一般建议

编辑1 我的另一个建议是在Windows开发机器上使用gcc和/或clang(以及Visual Studio)


3

这取决于您提到的“一些编译错误”。不知道它们是什么,就不可能具体。

我有适用于Windows / Linux / iOS / Android / Mac的跨平台代码。每个新平台在首次添加时都会带来一些额外的错误和警告。您将快速了解哪些结构会带来问题。要么避免它们,要么将差异抽象到带有#ifdefs 的标头中。尽量不要#ifdef在代码本身内的平台之间切换。

一个例子:

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

创建一个临时实例,返回MyClass后将其删除myfunction。在我的某些C ++编译器中,该实例是可读写的(并且它是临时的并且很快将被销毁,这一事实不必担心编译器)。与其他人一样,myfunction必须重新定义为const MyClass &,否则编译器会抱怨。C ++标准说什么或哪个编译器正确与错误都无关紧要。遇到错误几次我所知道的(a)在声明任何类型的临时变量MyClass并传递到myfunction或(b)宣布基准constmyfunction,用mutable在这里和那里deconstify。

底线:积累经验并制定自己的编码标准。


2
这是MSVC的错误功能。如果您的意思是在1个系统上进行开发可以允许这些漏洞悄悄地出现,请采取以下措施。但是,这不是您应该做的特定事情。
JDługosz

1
使用多个工具链的一件好事是,它们接受的通用子集比它们各自接受的更可能是正确的,符合标准的C ++。就您而言,标准显示的代码显然是错误的,并且您提到的两个修复都是有效的替代方法。我说这也没关系的标准说什么。
5gon12eder

1
或者我会说跨平台的C ++比标准所说的更具限制性。换句话说,即使标准如此规定,您仍然必须遵守所支持平台的最低公分母(或最低供应商能力)。有很多开源库必须排除C ++ 11,因为它们的一部分(例如在公民中)不具备C ++ 11功能。
rwong

3

帮助可移植性的一种可能方法是依赖C ++ 11标准提供的声明和功能,以及使用跨平台的库和框架(如POCOQt)

但是,即使这样也不是防故障的。记住格言

没有可移植程序之类的东西,只有成功移植到(某些特定平台)的程序

有了实践,纪律和丰富的经验,通常可以很快地将程序移植到另一个平台。但是经验和知识很重要。


1
另一个建议是,当由不同的人员和团队进行移植时,必须将代码更改重新集成到主线中。否则,平台差异将成为执行此任务的团队所ho积的知识。
rwong
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.