Merge pull request #661 from UnknownShadow200/CurlRewrite

Curl rewrite
This commit is contained in:
UnknownShadow200 2020-05-28 19:49:33 +10:00 committed by GitHub
commit b579825845
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 56 deletions

View File

@ -62,26 +62,26 @@ build_nix32() {
echo "Building linux32.."
cp $SOURCE_DIR/misc/CCicon_nix32 $SOURCE_DIR/src/CCicon_nix32.o
rm cc-nix32
gcc *.c $ALL_FLAGS $LINUX_FLAGS CCicon_nix32.o -DCC_COMMIT_SHA=\"$LATEST\" -m32 -o cc-nix32 -lX11 -lXi -lpthread -lGL -lm -lcurl -ldl
gcc *.c $ALL_FLAGS $LINUX_FLAGS CCicon_nix32.o -DCC_COMMIT_SHA=\"$LATEST\" -m32 -o cc-nix32 -lX11 -lXi -lpthread -lGL -lm -ldl
}
build_nix64() {
echo "Building linux64.."
cp $SOURCE_DIR/misc/CCicon_nix64 $SOURCE_DIR/src/CCicon_nix64.o
rm cc-nix64
gcc *.c $ALL_FLAGS $LINUX_FLAGS CCicon_nix64.o -DCC_COMMIT_SHA=\"$LATEST\" -m64 -o cc-nix64 -lX11 -lXi -lpthread -lGL -lm -lcurl -ldl
gcc *.c $ALL_FLAGS $LINUX_FLAGS CCicon_nix64.o -DCC_COMMIT_SHA=\"$LATEST\" -m64 -o cc-nix64 -lX11 -lXi -lpthread -lGL -lm -ldl
}
build_osx32() {
echo "Building mac32.."
rm cc-osx32
$MAC32_CC *.c $ALL_FLAGS -fvisibility=hidden -rdynamic -DCC_COMMIT_SHA=\"$LATEST\" -o cc-osx32 -framework Carbon -framework AGL -framework OpenAL -framework OpenGL -lcurl
$MAC32_CC *.c $ALL_FLAGS -fvisibility=hidden -rdynamic -DCC_COMMIT_SHA=\"$LATEST\" -o cc-osx32 -framework Carbon -framework AGL -framework OpenGL
}
build_osx64() {
echo "Building mac64.."
rm cc-osx64
$MAC64_CC *.c $ALL_FLAGS -fvisibility=hidden -rdynamic -DCC_COMMIT_SHA=\"$LATEST\" -o cc-osx64 -framework Cocoa -framework OpenAL -framework OpenGL -lcurl -lobjc
$MAC64_CC *.c $ALL_FLAGS -fvisibility=hidden -rdynamic -DCC_COMMIT_SHA=\"$LATEST\" -o cc-osx64 -framework Cocoa -framework OpenGL -lobjc
}
build_web() {
@ -101,7 +101,7 @@ build_rpi() {
echo "Building rpi.."
cp $SOURCE_DIR/misc/CCicon_rpi $SOURCE_DIR/src/CCicon_rpi.o
rm cc-rpi
$RPI_CC *.c $ALL_FLAGS $LINUX_FLAGS CCicon_rpi.o -DCC_COMMIT_SHA=\"$LATEST\" -o cc-rpi -DCC_BUILD_RPI -I ~/rpi/include -L ~/rpi/lib -lGLESv2 -lEGL -lX11 -lXi -lcurl -lm -lpthread -ldl -lrt -Wl,-rpath-link ~/rpi/lib
$RPI_CC *.c $ALL_FLAGS $LINUX_FLAGS CCicon_rpi.o -DCC_COMMIT_SHA=\"$LATEST\" -o cc-rpi -DCC_BUILD_RPI -I ~/rpi/include -L ~/rpi/lib -lGLESv2 -lEGL -lX11 -lXi -lm -lpthread -ldl -lrt -Wl,-rpath-link ~/rpi/lib
}
# -----------------------------

View File

@ -55,9 +55,9 @@ I am assuming you used the installer from http://www.mingw.org/
#### Linux
Install appropriate libs as required. For ubuntu these are: libx11-dev, libxi-dev, libgl1-mesa-dev, libcurl4-gnutls-dev or libcurl4-openssl-dev
Install appropriate libs as required. For ubuntu these are: libx11-dev, libxi-dev and libgl1-mesa-dev
```gcc *.c -o ClassiCube -lm -lpthread -lX11 -lXi -lGL -lcurl -ldl```
```gcc *.c -o ClassiCube -lm -lpthread -lX11 -lXi -lGL -ldl```
##### Cross compiling for windows:
@ -66,37 +66,37 @@ Install appropriate libs as required. For ubuntu these are: libx11-dev, libxi-de
##### Raspberry pi
Although the regular linux compiliation flags will work fine, to take full advantage of the hardware:
```gcc *.c -o ClassiCube -DCC_BUILD_RPI -lm -lpthread -lX11 -lEGL -lGLESv2 -lcurl -ldl```
```gcc *.c -o ClassiCube -DCC_BUILD_RPI -lm -lpthread -lX11 -lEGL -lGLESv2 -ldl```
#### macOS (32 bit)
```gcc *.c -o ClassiCube -framework Carbon -framework AGL -framework OpenGL -lcurl```
```gcc *.c -o ClassiCube -framework Carbon -framework AGL -framework OpenGL```
#### macOS (64 bit)
```gcc *.c -o ClassiCube -framework Cocoa -framework OpenGL -lcurl -lobjc```
```gcc *.c -o ClassiCube -framework Cocoa -framework OpenGL -lobjc```
#### FreeBSD
```clang *.c -o ClassiCube -I /usr/local/include -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lcurl -lexecinfo```
```clang *.c -o ClassiCube -I /usr/local/include -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lexecinfo```
#### OpenBSD
Install libexecinfo package if needed.
```gcc *.c -o ClassiCube -I /usr/X11R6/include -I /usr/local/include -L /usr/X11R6/lib -L /usr/local/lib -lX11 -lXi -lGL -lcurl -lexecinfo```
```gcc *.c -o ClassiCube -I /usr/X11R6/include -I /usr/local/include -L /usr/X11R6/lib -L /usr/local/lib -lX11 -lXi -lGL -lexecinfo```
#### NetBSD
```gcc *.c -o ClassiCube -I /usr/X11R7/include -I /usr/pkg/include -L /usr/X11R7/lib -L /usr/pkg/lib -lpthread -lX11 -lXi -lGL -lcurl -lexecinfo```
```gcc *.c -o ClassiCube -I /usr/X11R7/include -I /usr/pkg/include -L /usr/X11R7/lib -L /usr/pkg/lib -lpthread -lX11 -lXi -lGL -lexecinfo```
#### DragonflyBSD
```gcc *.c -o ClassiCube -I /usr/local/include -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lcurl -lexecinfo```
```gcc *.c -o ClassiCube -I /usr/local/include -L /usr/local/lib -lm -lpthread -lX11 -lXi -lGL -lexecinfo```
#### Solaris
```gcc *.c -o ClassiCube -lm -lsocket -lX11 -lXi -lGL -lcurl```
```gcc *.c -o ClassiCube -lm -lsocket -lX11 -lXi -lGL```
NOTE: You have to change entry->d_type == DT_DIR to Directory_Exists(&path) (TODO do this automatically)
@ -104,7 +104,7 @@ NOTE: You have to change entry->d_type == DT_DIR to Directory_Exists(&path) (TOD
Install libsdl2_devel, openal_devel, and libexecinfo_devel package if needed.
```gcc *.c -o ClassiCube -lm -lcurl -lexecinfo -lGL -lnetwork -lSDL2```
```gcc *.c -o ClassiCube -lm -lexecinfo -lGL -lnetwork -lSDL2```
NOTE: You have to change entry->d_type == DT_DIR to Directory_Exists(&path) (TODO do this automatically)

View File

@ -105,7 +105,7 @@ static void BuildPartVbs(struct ChunkPartInfo* info) {
count = info->Counts[i];
if (count) {
info->Vbs[i] = Gfx_CreateVb2(&Builder_Vertices[offset], VERTEX_FORMAT_P3FT2FC4B, count);
info->Vbs[i] = Gfx_CreateVb2(&Builder_Vertices[offset], VERTEX_FORMAT_TEXTURED, count);
offset += count;
} else {
info->Vbs[i] = 0;
@ -115,7 +115,7 @@ static void BuildPartVbs(struct ChunkPartInfo* info) {
count = info->SpriteCount;
offset = info->Offset;
if (count) {
info->Vbs[i] = Gfx_CreateVb2(&Builder_Vertices[offset], VERTEX_FORMAT_P3FT2FC4B, count);
info->Vbs[i] = Gfx_CreateVb2(&Builder_Vertices[offset], VERTEX_FORMAT_TEXTURED, count);
} else {
info->Vbs[i] = 0;
}
@ -398,7 +398,7 @@ static cc_bool BuildChunk(int x1, int y1, int z1, struct ChunkInfo* info) {
#else
/* NOTE: Relies on assumption vb is ignored by GL11 Gfx_LockVb implementation */
Builder_Vertices = (struct VertexTextured*)Gfx_LockVb(0,
VERTEX_FORMAT_P3FT2FC4B, totalVerts + 1);
VERTEX_FORMAT_TEXTURED, totalVerts + 1);
#endif
Builder_PostStretchTiles();

View File

@ -410,4 +410,4 @@ struct IGameComponent Gui_Component = {
Gui_Reset, /* Reset */
NULL, /* OnNewMap */
NULL, /* OnNewMapLoaded */
};
};

View File

@ -26,9 +26,6 @@
#elif defined CC_BUILD_WEB
/* Use fetch/XMLHttpRequest api for Emscripten */
#include <emscripten/fetch.h>
#elif defined CC_BUILD_CURL
#include <curl/curl.h>
#include <time.h>
#endif
void HttpRequest_Free(struct HttpRequest* request) {
@ -652,10 +649,90 @@ static void Http_SysFree(void) {
InternetCloseHandle(hInternet);
}
#elif defined CC_BUILD_CURL
#include "Errors.h"
#include <stddef.h>
typedef void CURL;
struct curl_slist;
typedef int CURLcode;
#define CURL_GLOBAL_DEFAULT ((1<<0) | (1<<1)) /* SSL and Win32 options */
#define CURLOPT_WRITEDATA (10000 + 1)
#define CURLOPT_URL (10000 + 2)
#define CURLOPT_ERRORBUFFER (10000 + 10)
#define CURLOPT_WRITEFUNCTION (20000 + 11)
#define CURLOPT_POSTFIELDS (10000 + 15)
#define CURLOPT_USERAGENT (10000 + 18)
#define CURLOPT_HTTPHEADER (10000 + 23)
#define CURLOPT_HEADERDATA (10000 + 29)
#define CURLOPT_VERBOSE (0 + 41)
#define CURLOPT_HEADER (0 + 42)
#define CURLOPT_NOBODY (0 + 44)
#define CURLOPT_POST (0 + 47)
#define CURLOPT_FOLLOWLOCATION (0 + 52)
#define CURLOPT_POSTFIELDSIZE (0 + 60)
#define CURLOPT_MAXREDIRS (0 + 68)
#define CURLOPT_HEADERFUNCTION (20000 + 79)
#define CURLOPT_HTTPGET (0 + 80)
#if defined _WIN32
#define APIENTRY __cdecl
#else
#define APIENTRY
#endif
typedef CURLcode (APIENTRY *FP_curl_global_init)(long flags); static FP_curl_global_init _curl_global_init;
typedef void (APIENTRY *FP_curl_global_cleanup)(void); static FP_curl_global_cleanup _curl_global_cleanup;
typedef CURL* (APIENTRY *FP_curl_easy_init)(void); static FP_curl_easy_init _curl_easy_init;
typedef CURLcode (APIENTRY *FP_curl_easy_perform)(CURL *c); static FP_curl_easy_perform _curl_easy_perform;
typedef CURLcode (APIENTRY *FP_curl_easy_setopt)(CURL *c, int opt, ...); static FP_curl_easy_setopt _curl_easy_setopt;
typedef void (APIENTRY *FP_curl_easy_cleanup)(CURL* c); static FP_curl_easy_cleanup _curl_easy_cleanup;
typedef const char* (APIENTRY *FP_curl_easy_strerror)(CURLcode res); static FP_curl_easy_strerror _curl_easy_strerror;
typedef void (APIENTRY *FP_curl_slist_free_all)(struct curl_slist* l); static FP_curl_slist_free_all _curl_slist_free_all;
typedef struct curl_slist* (APIENTRY *FP_curl_slist_append)(struct curl_slist* l, const char* v); static FP_curl_slist_append _curl_slist_append;
/* End of curl headers */
#if defined CC_BUILD_WIN
static const String curlLib = String_FromConst("libcurl.dll");
static const String curlAlt = String_FromConst("curl.dll");
#elif defined CC_BUILD_OSX
static const String curlLib = String_FromConst("/usr/lib/libcurl.4.dylib");
static const String curlAlt = String_FromConst("/usr/lib/libcurl.dylib");
#elif defined CC_BUILD_OPENBSD
static const String curlLib = String_FromConst("libcurl.so.25.17");
static const String curlAlt = String_FromConst("libcurl.so.25.16");
#else
static const String curlLib = String_FromConst("libcurl.so.4");
static const String curlAlt = String_FromConst("libcurl.so.3");
#endif
#define QUOTE(x) #x
#define LoadCurlFunc(sym) (_ ## sym = (FP_ ## sym)DynamicLib_Get2(lib, QUOTE(sym)))
static cc_bool LoadCurlFuncs(void) {
void* lib = DynamicLib_Load2(&curlLib);
if (!lib) {
Logger_DynamicLibWarn("loading", &curlLib);
lib = DynamicLib_Load2(&curlAlt);
if (!lib) { Logger_DynamicLibWarn("loading", &curlAlt); return false; }
}
/* Non-essential function missing in older curl versions */
LoadCurlFunc(curl_easy_strerror);
return
LoadCurlFunc(curl_global_init) && LoadCurlFunc(curl_global_cleanup) &&
LoadCurlFunc(curl_easy_init) && LoadCurlFunc(curl_easy_perform) &&
LoadCurlFunc(curl_easy_setopt) && LoadCurlFunc(curl_easy_cleanup) &&
LoadCurlFunc(curl_slist_free_all) && LoadCurlFunc(curl_slist_append);
}
static CURL* curl;
static cc_bool curlSupported;
cc_bool Http_DescribeError(cc_result res, String* dst) {
const char* err = curl_easy_strerror((CURLcode)res);
const char* err;
if (!_curl_easy_strerror) return false;
err = _curl_easy_strerror((CURLcode)res);
if (!err) return false;
String_AppendConst(dst, err);
@ -663,11 +740,16 @@ cc_bool Http_DescribeError(cc_result res, String* dst) {
}
static void Http_SysInit(void) {
CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
if (res) Logger_Abort2(res, "Failed to init curl");
static const String msg = String_FromConst("Failed to init libcurl. All HTTP requests will therefore fail.");
CURLcode res;
curl = curl_easy_init();
if (!curl) Logger_Abort("Failed to init easy curl");
if (!LoadCurlFuncs()) { Logger_WarnFunc(&msg); return; }
res = _curl_global_init(CURL_GLOBAL_DEFAULT);
if (res) { Logger_SimpleWarn(res, "initing curl"); return; }
curl = _curl_easy_init();
if (!curl) { Logger_SimpleWarn(res, "initing curl_easy"); return; }
curlSupported = true;
}
static struct curl_slist* headers_list;
@ -677,7 +759,7 @@ static void Http_AddHeader(const char* key, const String* value) {
String_Format2(&tmp, "%c: %s", key, value);
tmp.buffer[tmp.length] = '\0';
headers_list = curl_slist_append(headers_list, tmp.buffer);
headers_list = _curl_slist_append(headers_list, tmp.buffer);
}
/* Processes a HTTP header downloaded from the server */
@ -707,14 +789,14 @@ static size_t Http_ProcessData(char *buffer, size_t size, size_t nitems, void* u
/* Sets general curl options for a request */
static void Http_SetCurlOpts(struct HttpRequest* req) {
curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 20L);
_curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
_curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
_curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 20L);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_ProcessHeader);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_ProcessData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
_curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_ProcessHeader);
_curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
_curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_ProcessData);
_curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
}
static cc_result Http_SysDo(struct HttpRequest* req, String* url) {
@ -722,41 +804,49 @@ static cc_result Http_SysDo(struct HttpRequest* req, String* url) {
void* post_data = req->data;
CURLcode res;
curl_easy_reset(curl);
if (!curlSupported) {
HttpRequest_Free(req);
return ERR_NOT_SUPPORTED;
}
headers_list = NULL;
Http_SetRequestHeaders(req);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers_list);
_curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers_list);
Http_SetCurlOpts(req);
Platform_ConvertString(urlStr, url);
curl_easy_setopt(curl, CURLOPT_URL, urlStr);
_curl_easy_setopt(curl, CURLOPT_URL, urlStr);
if (req->requestType == REQUEST_TYPE_HEAD) {
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
_curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
} else if (req->requestType == REQUEST_TYPE_POST) {
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->size);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->data);
_curl_easy_setopt(curl, CURLOPT_POST, 1L);
_curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->size);
_curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->data);
/* per curl docs, we must persist POST data until request finishes */
req->data = NULL;
HttpRequest_Free(req);
} else {
/* Undo POST/HEAD state */
_curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
}
bufferSize = 0;
http_curProgress = ASYNC_PROGRESS_FETCHING_DATA;
res = curl_easy_perform(curl);
res = _curl_easy_perform(curl);
http_curProgress = 100;
curl_slist_free_all(headers_list);
_curl_slist_free_all(headers_list);
/* can free now that request has finished */
Mem_Free(post_data);
return res;
}
static void Http_SysFree(void) {
curl_easy_cleanup(curl);
curl_global_cleanup();
if (!curlSupported) return;
_curl_easy_cleanup(curl);
_curl_global_cleanup();
}
#elif defined CC_BUILD_ANDROID
struct HttpRequest* java_req;

View File

@ -30,15 +30,15 @@ LIBS=-mwindows -lws2_32 -lwininet -lwinmm -limagehlp -lcrypt32 -ld3d9
endif
ifeq ($(PLAT),linux)
LIBS=-lX11 -lXi -lpthread -lGL -lm -ldl -lcurl
LIBS=-lX11 -lXi -lpthread -lGL -lm -ldl
endif
ifeq ($(PLAT),sunos)
LIBS=-lm -lsocket -lX11 -lXi -lGL -lcurl
LIBS=-lm -lsocket -lX11 -lXi -lGL
endif
ifeq ($(PLAT),darwin)
LIBS=-lcurl
LIBS=
LDFLAGS=-rdynamic -framework Carbon -framework AGL -framework OpenGL
endif
@ -46,31 +46,31 @@ ifeq ($(PLAT),freebsd)
CC=clang
CFLAGS=-g -pipe -rdynamic -I /usr/local/include -fno-math-errno
LDFLAGS=-L /usr/local/lib
LIBS=-lcurl -lexecinfo -lGL -lX11 -lXi -lm -lpthread
LIBS=-lexecinfo -lGL -lX11 -lXi -lm -lpthread
endif
ifeq ($(PLAT),openbsd)
CFLAGS=-g -pipe -rdynamic -I /usr/X11R6/include -I /usr/local/include -fno-math-errno
LDFLAGS=-L /usr/X11R6/lib -L /usr/local/lib
LIBS=-lcurl -lexecinfo -lGL -lX11 -lXi
LIBS=-lexecinfo -lGL -lX11 -lXi
endif
ifeq ($(PLAT),netbsd)
CFLAGS=-g -pipe -rdynamic -I /usr/X11R7/include -I /usr/pkg/include -fno-math-errno
LDFLAGS=-L /usr/X11R7/lib -L /usr/pkg/lib
LIBS=-lcurl -lexecinfo -lGL -lX11 -lXi
LIBS=-lexecinfo -lGL -lX11 -lXi
endif
ifeq ($(PLAT),dragonfly)
CFLAGS=-g -pipe -rdynamic -I /usr/local/include -fno-math-errno
LDFLAGS=-L /usr/local/lib
LIBS=-lcurl -lexecinfo -lGL -lX11 -lXi -lm -lpthread
LIBS=-lexecinfo -lGL -lX11 -lXi -lm -lpthread
endif
ifeq ($(PLAT),haiku)
CFLAGS=-g -pipe -fno-math-errno
LDFLAGS=-g
LIBS=-lcurl -lm -lexecinfo -lGL -lnetwork -lSDL2
LIBS=-lm -lexecinfo -lGL -lnetwork -lSDL2
endif
ifeq ($(OS),Windows_NT)

View File

@ -47,7 +47,6 @@ const cc_result ReturnCode_SocketWouldBlock = WSAEWOULDBLOCK;
#include <dirent.h>
#include <fcntl.h>
#include <pthread.h>
#include <dlfcn.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
@ -1392,8 +1391,46 @@ cc_bool DynamicLib_DescribeError(String* dst) {
void* DynamicLib_Load2(const String* path) { return NULL; }
void* DynamicLib_Get2(void* lib, const char* name) { return NULL; }
cc_bool DynamicLib_DescribeError(String* dst) { return false; }
#elif defined CC_BUILD_OSX && __ppc__
/* TODO: Only do it for macOS < 10.4 */
const String DynamicLib_Ext = String_FromConst(".dylib");
void* DynamicLib_Load2(const String* path) {
char str[NATIVE_STR_LEN];
Platform_ConvertString(str, path);
return NSAddImage(str, NSADDIMAGE_OPTION_WITH_SEARCHING |
NSADDIMAGE_OPTION_RETURN_ON_ERROR);
}
void* DynamicLib_Get2(void* lib, const char* name) {
String tmp; char tmpBuffer[128];
NSSymbol sym;
String_InitArray_NT(tmp, tmpBuffer);
/* NS linker api rquires symbols to have a _ prefix */
String_Append(&tmp, '_');
String_AppendConst(&tmp, name);
tmp.buffer[tmp.length] = '\0';
sym = NSLookupSymbolInImage(lib, tmp.buffer, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
return sym ? NSAddressOfSymbol(sym) : NULL;
}
cc_bool DynamicLib_DescribeError(String* dst) {
NSLinkEditErrors err = 0;
const char* name = "";
const char* msg = "";
int errNum = 0;
NSLinkEditError(&err, &errNum, &name, &msg);
String_Format4(dst, "%c in %c (%i, sys %i)", msg, name, &err, &errNum);
return true;
}
#elif defined CC_BUILD_POSIX
#include <dlfcn.h>
/* TODO: Should we use .bundle instead of .dylib? */
#ifdef CC_BUILD_OSX
const String DynamicLib_Ext = String_FromConst(".dylib");
#else