如何使用预处理器创建跨平台库?

时间:2011-11-10 16:13:17

标签: c++ graphics cross-platform c-preprocessor platform

我想使用WxWidgets,SDL等使用的相同#ifdef方法。唯一的问题是我不知道如何使用它。

说我想创建一个绘制矩形的类。我希望它在X11平台(即linux)和win32平台上的GDI上使用cairo:

class graphics
{
void drawRect(int x, int y, int w, int h)
{
/*if on win32*/
HDC myHdc = ::BeginPaint(myHwnd,&mypstr);
::Rectangle(myHdc,x,y,w,h); 
::EndPaint(myHwnd,&mypstr);

/*if on x11*/
cairo_surface_t* s = cairo_xlib_surface_create(/* args */); 
cairo_t* c = cairo_create(s);
cairo_rectangle(c,x,y,w,h);
// etc. etc.
}
};

我如何使用#ifdef或其他内容来执行此操作?

6 个答案:

答案 0 :(得分:3)

如果可以,请更喜欢将特定于平台的方法放入单独的翻译单元中。这将使清洁和代码更易读,更易于开发和维护。恕我直言,构建过程应确定要合并的平台特定模块。

例如:
rectangle.hpp:

struct Rectangle
{
  void draw(int upper_left_corner_x, int upper_left_corner_y,
            unsigned int length, unsigned int width);
}

现在平台特定文件:
rectangle_wx_widgets.cpp:

#include "rectangle.hpp"
void
Rectangle ::
draw(int upper_left_corner_x, int upper_left_corner_y,
            unsigned int length, unsigned int width)
{
// wxWidgets specific code here.
}

rectangle_qt.cpp:

#include "rectangle.hpp"
void
Rectangle ::
draw(int upper_left_corner_x, int upper_left_corner_y,
            unsigned int length, unsigned int width)
{
// QT specific code here.
}

<强> main.cpp中:

#include "rectangl.hpp"
int main(void)
{
  Rectangle r;
  r.draw(50, 50, 10, 5);
  return 0;
}

上面的代码没有条件预处理程序指令。无论平台如何,main函数都会绘制一个矩形。平台的细节已从main中删除,因为它们并不重要。因此,在不更改任何编译器开关或担心定义哪个预处理器标识符的情况下,可以看到main无条件地绘制矩形。

要使用wxWidgets平台进行绘制,构建过程将使用rectangle_wx_widgets.cpp。要使用QT绘制,将使用rectangle_qt.cpp文件,但不能同时使用两者。如此图所示,为了生成任一平台的代码,不会更改任何代码。可以定制构建过程,以便命令build wxWidgets包含正确的翻译单元。因此,将参数传递给构建过程会生成特定于平台的可执行文件。

答案 1 :(得分:2)

跨平台并不仅仅意味着unix vs windows。此外,预定义的cpp指令可能依赖于编译器。 提升平台选择源代码是一个良好的开端,看看如何以正确的方式做到这一点。见config/select_platform_config.hpp 您可能还想查看设置cmake

platform dependent defines

答案 2 :(得分:0)

他们非常直接。

你想要这样的东西:

#ifndef WIN32
// something for X11
#else
// something for Windows
#endif

这只是知道默认条件的问题(在这种情况下就像WIN32)。操作系统,编译器和许多可移植性的东西都有条件。

对于这种情况,请查看windows.h头文件。它可能包含更多信息。

答案 3 :(得分:0)

您可以使用预定义的平台变量,如WIN3​​2:

#ifdef WIN32
....
#else
....
#endif

答案 4 :(得分:0)

有关特定于平台的宏的列表,另请参阅http://www.netbsd.org/docs/pkgsrc/fixes.html#fixes.build.cpp

答案 5 :(得分:0)

有一个技巧,我没有看到其他人提到(编辑:sysfault提到它)。这里有两个不同的概念。预处理器命令将根据您的目标和编译器而有所不同。即,告诉您正在使用哪个编译器(GCC vs MSVC

#ifdef _MSC_VER
    /*MSVC*/
#endif
#ifdef __GNUC__
    /*GCC*/
#endif

MSVC将仅针对Windows目标进行编译(就我们今天所关注的而言),GCC将针对所有目标。对于GCC,要告诉它所针对的操作系统:

#ifdef __MINGW32__ 
    /* Windows */
#endif
#ifdef BSD
    /* BSD */
#endif
#ifdef __linux__
    /* linux */
#endif
#ifdef __APPLE__
    /* OSX */
#endif

此外,有时您需要了解处理器特有的内容,而不是操作系统:

__CHAR_UNSIGNED__
    GCC defines this macro if and only if the data type char is unsigned on the target machine.
__BYTE_ORDER__
__ORDER_LITTLE_ENDIAN__
__ORDER_BIG_ENDIAN__
__ORDER_PDP_ENDIAN__
    __BYTE_ORDER__ is defined to one of the values __ORDER_LITTLE_ENDIAN__, __ORDER_BIG_ENDIAN__, or __ORDER_PDP_ENDIAN__ to reflect the layout of multi-byte and multi-word quantities in memory.
__LP64__
_LP64
    These macros are defined, with value 1, if (and only if) the compilation is for a target where long int and pointer both use 64-bits and int uses 32-bit. 

还有很多其他人