Как вы используете препроцессор для создания кроссплатформенной библиотеки? - PullRequest
5 голосов
/ 10 ноября 2011

Я хочу использовать тот же #ifdef подход, который используется в WxWidgets, SDL и т. Д. Единственная проблема - я не знаю, как его использовать.

Скажем, я хочу создать класс, который рисует прямоугольник. Я хочу использовать cairo на платформах X11 (т.е. linux) и GDI на платформах win32:

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 ]

3 голосов
/ 10 ноября 2011

Если вы можете, предпочитайте помещать специфичные для платформы методы в отдельные единицы перевода. Это позволит чище и более читаемый код и легче разрабатывать и поддерживать. ИМХО, процесс сборки должен определять, какие модули для конкретной платформы включать.

Например:
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 включала правильные единицы перевода. Таким образом, передача параметра в процесс сборки создает исполняемый файл для конкретной платформы.

2 голосов
/ 10 ноября 2011

кроссплатформенность означает не только Unix против Windows.также предопределенные директивы cpp могут зависеть от компилятора.хороший исходный код для выбора платформы - хорошее начало, чтобы увидеть, как это можно сделать правильно.см. config / select_platform_config.hpp вы также можете взглянуть на cmake , который устанавливает зависимые от платформы определения

0 голосов
/ 10 ноября 2011

Есть хитрость, о которой я не вижу, чтобы другие упоминали (правка: sysfault упомянул об этом). Здесь работают две разные концепции. Команды препроцессора будут отличаться в зависимости от вашей цели и вашего компилятора. А именно, чтобы сказать, какой компилятор вы используете ( GCC против 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. 

и многие другие

0 голосов
/ 10 ноября 2011

Список макросов для конкретной платформы см. Также http://www.netbsd.org/docs/pkgsrc/fixes.html#fixes.build.cpp

0 голосов
/ 10 ноября 2011

Существуют предопределенные переменные платформы, такие как WIN32, которые вы можете использовать:

#ifdef WIN32
....
#else
....
#endif
0 голосов
/ 10 ноября 2011

Они довольно прямые.

Вы хотите что-то вроде этого:

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

Это просто вопрос знания условных выражений по умолчанию (например, WIN32 в данном случае).Есть условные обозначения для операционной системы, компиляторов и множества переносимых вещей.

Для этого случая посмотрите файл заголовка windows.h.Может содержать больше информации для вас.

...