我的做法很簡單,就是定義一個標頭檔nPlatform.h,讓其他的程式碼一定要include進來,這樣就可以在編譯(compile)知道是哪一個平台了。
#ifndef nPlatform_h
#define nPlatform_h
#if (defined(NS_WIN32) || defined(WIN32))
#define NS_PLATFORM_WIN32 1
#define NS_PLATFORM_WINDOWS 1
#elif (defined(_WIN32_WCE) || defined(NS_WINCE))
#define NS_PLATFORM_WINCE 1
#define NS_PLATFORM_WINDOWS 1
#elif (defined(__ANDROID__) || defined(NS_ANDROID))
#define NS_PLATFORM_ANDROID 1
#define NS_PLATFORM_LINUX 1
#elif (defined(__APPLE__))
#define NS_APPLE 1
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
// iOS Simulator
#define NS_PLATFORM_IOS 1
#elif TARGET_OS_IPHONE
// iOS device
#define NS_PLATFORM_IOS 1
#elif TARGET_OS_MAC
// Other kinds of Mac OS
#define NS_PLATFORM_OSX 1
#else
// Unsupported platform
DASSERT(0);
#endif
#else
DASSERT(0);
#endif
#endif // nPlatform_h
從上面的程式碼可以知道,在Mac裡頭是使用#elif (defined(__APPLE__))來決定編譯環境的,一旦程式檔include這個標頭檔,就可以知道目前的平台了。
其實為了避免,不同平台的函式呼叫散步在這個項目中,通常會在底層的部分將這些不同函式呼叫集中起來,上層一律使用包裝過的類別或者Api,就可以將跨平台的移植負擔最小化。
舉個例子,我會將檔案存取(file access)的函式特別包裝一個類別,實作的部分會根據不同平台使用不同的函式,上層程式碼就一律呼叫這個特定的類別,這樣發展就可以簡單了一些。
nsFile類別
/*
* class for file
*/
// define SEEK method.
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
class nsFile
{
public:
enum StateType_E
{
IFEXIST = 0x01,
IFDIR = 0x02,
IFREG = 0x04
};
static const char DELM;
static const char* DELM_STR;
static const wchar_t DELM_W;
static const wchar_t* DELM_STR_W;
static int stat(const nsUChar_T* filename);
static bool isAbsPath(const nsUChar_T* full_path);
static bool isExecutable(const nsUChar_T* filename);
static long getSize(const nsUChar_T* filename);
static bool copy(const nsUChar_T* src, const nsUChar_T* dest);
static bool remove(const nsUChar_T* filename);
static bool move(const nsUChar_T* src, const nsUChar_T* dest);
static bool isDir(const nsUChar_T* filename) { return (stat(filename)&IFDIR)?true:false; }
static bool isRegular(const nsUChar_T* filename) { return (stat(filename)&IFREG)?true:false; }
static bool isExist(const nsUChar_T* filename) { return (stat(filename)&IFEXIST)?true:false; }
enum Mode_E
{
eREAD = 0x01,
eWRITE = 0x02,
//eAPPEND = 0x04
};
nsFile();
~nsFile();
bool open(const nsUChar_T* path, int mode);
void close();
void flush();
U64 size();
U64 seek(U64 offset, int origin);
U64 tell();
U32 read(void*, U32, U32);
U32 write(void*, U32, U32);
private:
int _mode;
#ifdef NS_PLATFORM_WINDOWS
FILE* _fd;
#elif NS_APPLE
FILE* _fd;
#else
int _fd;
//FILE* _fd;
#endif
};
nsFile類別實作範例
bool
nsFile::open(const nsUChar_T* path, int mode)
{
_mode = mode;
#ifdef NS_PLATFORM_WIN32
if (mode&eREAD) {
_fd = _wfopen((wchar_t*)path, L"rb+");
}
else if (mode&eWRITE) {
_fd = _wfopen((wchar_t*)path, L"wb+");
}
#elif NS_PLATFORM_OSX
static char cpath[1024];
memset(cpath, 0, 1024);
nsUStr::toMultiBytes(path, cpath, 1024);
if (mode&eREAD) {
_fd = fopen(cpath, "rb+");
}
else if (mode&eWRITE) {
_fd = fopen(cpath, "wb+");
}
#else
static char cpath[1024];
memset(cpath, 0, 1024);
nsUStr::toMultiBytes(path, cpath, 1024);
if (mode&eREAD) {
_fd = ::open(cpath, O_RDONLY);
}
else if (mode&eWRITE) {
_fd = ::open(cpath, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
}
endif
return ((_fd)?true:false);
}
void
nsFile::close()
{
if (_fd) {
#ifdef NS_PLATFORM_WINDOWS
fclose(_fd);
#elif NS_APPLE
fclose(_fd);
#else
::close(_fd);
#endif
}
}
其實,上面的範例其實可以在Windows,OSX,Linux(Android)三個平台正常使用的,是我已經驗證過的。
沒有留言:
張貼留言