diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c23b3d..a927f28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,11 +25,12 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() if(WIN32) -list(APPEND CORE_EXTRA src/win32_largefilewrapper.c) -elseif(APPLE) -list(APPEND CORE_EXTRA src/osx_largefilewrapper.c) -elseif(GEKKO) -list(APPEND CORE_EXTRA src/gekko_support.c) +list(APPEND CORE_EXTRA src/win32_largefilewrapper.c include/win32_largefilewrapper.h) +elseif(APPLE OR GEKKO) +list(APPEND CORE_EXTRA src/osx_largefilewrapper.c include/osx_largefilewrapper.h) +if(GEKKO) +list(APPEND CORE_EXTRA src/gekko_support.c include/gekko_support.h) +endif() endif() add_library(AthenaCore @@ -68,7 +69,6 @@ add_library(AthenaCore include/LZ77/LZType11.hpp include/Athena/FileInfo.hpp include/Athena/Dir.hpp - include/gekko_support.h include/Athena/DNA.hpp include/Athena/DNAYaml.hpp include/yaml.h @@ -117,7 +117,7 @@ add_library(AthenaWiiSave EXCLUDE_FROM_ALL include/md5.h include/sha1.h ) -if(NOT MSVC) +if(NOT MSVC AND NOT GEKKO) set_source_files_properties(src/aes.cpp PROPERTIES COMPILE_FLAGS -maes) endif() @@ -227,7 +227,9 @@ install(EXPORT AthenaTargets DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT Athena) # atdna import # ################ +if(NOT GEKKO) add_subdirectory(atdna) +endif() ######### # CPack # diff --git a/include/Athena/DNAYaml.hpp b/include/Athena/DNAYaml.hpp index 6294ae3..8cf37bf 100644 --- a/include/Athena/DNAYaml.hpp +++ b/include/Athena/DNAYaml.hpp @@ -7,6 +7,10 @@ * Any changes to the types or namespacing must be reflected in 'atdna/main.cpp' */ +#ifdef GEKKO +#include +#include +#endif #include #include #include diff --git a/include/gekko_support.h b/include/gekko_support.h index 84e2f33..0650ae7 100644 --- a/include/gekko_support.h +++ b/include/gekko_support.h @@ -4,6 +4,9 @@ #ifdef GEKKO #include #include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -12,7 +15,14 @@ char * realpath(const char *path, char *resolved); int vsnprintf (char *s, size_t n, const char *format, va_list ap); - +int +snprintf(char *str, size_t n, const char *fmt, ...); +long long +strtoq(const char *nptr, char **endptr, int base); +unsigned long long +strtouq(const char *nptr, char **endptr, int base); +float +strtof(const char *string, char **endPtr ); #ifdef __cplusplus } #endif diff --git a/include/osx_largefilewrapper.h b/include/osx_largefilewrapper.h index 0e83b9a..b188255 100644 --- a/include/osx_largefilewrapper.h +++ b/include/osx_largefilewrapper.h @@ -1,7 +1,7 @@ #ifndef OSX_LARGEFILEWRAPPER_H #define OSX_LARGEFILEWRAPPER_H -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(GEKKO) #include #ifdef __cplusplus extern "C" { diff --git a/src/Athena/FileReader.cpp b/src/Athena/FileReader.cpp index f517f3a..10a48bc 100644 --- a/src/Athena/FileReader.cpp +++ b/src/Athena/FileReader.cpp @@ -4,6 +4,9 @@ #include "win32_largefilewrapper.h" #elif __APPLE__ #include "osx_largefilewrapper.h" +#elif GEKKO +#include "gekko_support.h" +#include "osx_largefilewrapper.h" #endif namespace Athena diff --git a/src/Athena/FileWriter.cpp b/src/Athena/FileWriter.cpp index 7376d47..6a2eb1c 100644 --- a/src/Athena/FileWriter.cpp +++ b/src/Athena/FileWriter.cpp @@ -4,6 +4,9 @@ #include "win32_largefilewrapper.h" #elif __APPLE__ #include "osx_largefilewrapper.h" +#elif GEKKO +#include "gekko_support.h" +#include "osx_largefilewrapper.h" #endif namespace Athena diff --git a/src/aes.cpp b/src/aes.cpp index 7fd617e..470d723 100644 --- a/src/aes.cpp +++ b/src/aes.cpp @@ -3,7 +3,7 @@ #include #if _WIN32 #include -#else +#elif !GEKKO #include #endif diff --git a/src/gekko_support.c b/src/gekko_support.c index b4a0193..d8d2b5b 100644 --- a/src/gekko_support.c +++ b/src/gekko_support.c @@ -21,219 +21,200 @@ * components. Returns (resolved) on success, or (NULL) on failure, * in which case the path which caused trouble is left in (resolved). */ -char * -realpath(const char *path, char *resolved) -{ - struct stat sb; - char *p, *q, *s; - size_t left_len, resolved_len; - unsigned symlinks; - int serrno, slen, mem_allocated; - char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; +char *realpath(const char *path, char *resolved) { + struct stat sb; + char *p, *q, *s; + size_t left_len, resolved_len; + unsigned symlinks; + int serrno, slen, mem_allocated; + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; - if (path[0] == '\0') { - errno = ENOENT; - return (NULL); - } + if (path[0] == '\0') { + errno = ENOENT; + return (NULL); + } - serrno = errno; + serrno = errno; - if (resolved == NULL) { - resolved = malloc(PATH_MAX); - if (resolved == NULL) - return (NULL); - mem_allocated = 1; - } else - mem_allocated = 0; + if (resolved == NULL) { + resolved = malloc(PATH_MAX); + if (resolved == NULL) return (NULL); + mem_allocated = 1; + } else + mem_allocated = 0; - symlinks = 0; - if (path[0] == '/') { - resolved[0] = '/'; - resolved[1] = '\0'; - if (path[1] == '\0') - return (resolved); - resolved_len = 1; - left_len = strlcpy(left, path + 1, sizeof(left)); - } else { - if (getcwd(resolved, PATH_MAX) == NULL) { - if (mem_allocated) - free(resolved); - else - strlcpy(resolved, ".", PATH_MAX); - return (NULL); - } - resolved_len = strlen(resolved); - left_len = strlcpy(left, path, sizeof(left)); - } - if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { - errno = ENAMETOOLONG; - goto err; - } + symlinks = 0; + if (path[0] == '/') { + resolved[0] = '/'; + resolved[1] = '\0'; + if (path[1] == '\0') return (resolved); + resolved_len = 1; + left_len = strlcpy(left, path + 1, sizeof(left)); + } else { + if (getcwd(resolved, PATH_MAX) == NULL) { + if (mem_allocated) + free(resolved); + else + strlcpy(resolved, ".", PATH_MAX); + return (NULL); + } + resolved_len = strlen(resolved); + left_len = strlcpy(left, path, sizeof(left)); + } + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } - /* - * Iterate over path components in `left'. - */ - while (left_len != 0) { - /* - * Extract the next path component and adjust `left' - * and its length. - */ - p = strchr(left, '/'); - s = p ? p : left + left_len; - if (s - left >= sizeof(next_token)) { - errno = ENAMETOOLONG; - goto err; - } - memcpy(next_token, left, s - left); - next_token[s - left] = '\0'; - left_len -= s - left; - if (p != NULL) - memmove(left, s + 1, left_len + 1); - if (resolved[resolved_len - 1] != '/') { - if (resolved_len + 1 >= PATH_MAX) { - errno = ENAMETOOLONG; - goto err; - } - resolved[resolved_len++] = '/'; - resolved[resolved_len] = '\0'; - } - if (next_token[0] == '\0') - continue; - else if (strcmp(next_token, ".") == 0) - continue; - else if (strcmp(next_token, "..") == 0) { - /* - * Strip the last path component except when we have - * single "/" - */ - if (resolved_len > 1) { - resolved[resolved_len - 1] = '\0'; - q = strrchr(resolved, '/') + 1; - *q = '\0'; - resolved_len = q - resolved; - } - continue; - } + /* + * Iterate over path components in `left'. + */ + while (left_len != 0) { + /* + * Extract the next path component and adjust `left' + * and its length. + */ + p = strchr(left, '/'); + s = p ? p : left + left_len; + if (s - left >= sizeof(next_token)) { + errno = ENAMETOOLONG; + goto err; + } + memcpy(next_token, left, s - left); + next_token[s - left] = '\0'; + left_len -= s - left; + if (p != NULL) memmove(left, s + 1, left_len + 1); + if (resolved[resolved_len - 1] != '/') { + if (resolved_len + 1 >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } + resolved[resolved_len++] = '/'; + resolved[resolved_len] = '\0'; + } + if (next_token[0] == '\0') + continue; + else if (strcmp(next_token, ".") == 0) + continue; + else if (strcmp(next_token, "..") == 0) { + /* + * Strip the last path component except when we have + * single "/" + */ + if (resolved_len > 1) { + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + continue; + } - /* - * Append the next path component and lstat() it. If - * lstat() fails we still can return successfully if - * there are no more path components left. - */ - resolved_len = strlcat(resolved, next_token, PATH_MAX); - if (resolved_len >= PATH_MAX) { - errno = ENAMETOOLONG; - goto err; - } - if (lstat(resolved, &sb) != 0) { - if (errno == ENOENT && p == NULL) { - errno = serrno; - return (resolved); - } - goto err; - } - if (S_ISLNK(sb.st_mode)) { - if (symlinks++ > SYMLOOP_MAX) { - errno = ELOOP; - goto err; - } - slen = readlink(resolved, symlink, sizeof(symlink) - 1); - if (slen < 0) - goto err; - symlink[slen] = '\0'; - if (symlink[0] == '/') { - resolved[1] = 0; - resolved_len = 1; - } else if (resolved_len > 1) { - /* Strip the last path component. */ - resolved[resolved_len - 1] = '\0'; - q = strrchr(resolved, '/') + 1; - *q = '\0'; - resolved_len = q - resolved; - } + /* + * Append the next path component and lstat() it. If + * lstat() fails we still can return successfully if + * there are no more path components left. + */ + resolved_len = strlcat(resolved, next_token, PATH_MAX); + if (resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } + if (lstat(resolved, &sb) != 0) { + if (errno == ENOENT && p == NULL) { + errno = serrno; + return (resolved); + } + goto err; + } + if (S_ISLNK(sb.st_mode)) { + if (symlinks++ > SYMLOOP_MAX) { + errno = ELOOP; + goto err; + } + slen = readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) goto err; + symlink[slen] = '\0'; + if (symlink[0] == '/') { + resolved[1] = 0; + resolved_len = 1; + } else if (resolved_len > 1) { + /* Strip the last path component. */ + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } - /* - * If there are any path components left, then - * append them to symlink. The result is placed - * in `left'. - */ - if (p != NULL) { - if (symlink[slen - 1] != '/') { - if (slen + 1 >= sizeof(symlink)) { - errno = ENAMETOOLONG; - goto err; - } - symlink[slen] = '/'; - symlink[slen + 1] = 0; - } - left_len = strlcat(symlink, left, sizeof(symlink)); - if (left_len >= sizeof(left)) { - errno = ENAMETOOLONG; - goto err; - } - } - left_len = strlcpy(left, symlink, sizeof(left)); - } - } + /* + * If there are any path components left, then + * append them to symlink. The result is placed + * in `left'. + */ + if (p != NULL) { + if (symlink[slen - 1] != '/') { + if (slen + 1 >= sizeof(symlink)) { + errno = ENAMETOOLONG; + goto err; + } + symlink[slen] = '/'; + symlink[slen + 1] = 0; + } + left_len = strlcat(symlink, left, sizeof(symlink)); + if (left_len >= sizeof(left)) { + errno = ENAMETOOLONG; + goto err; + } + } + left_len = strlcpy(left, symlink, sizeof(left)); + } + } - /* - * Remove trailing slash except when the resolved pathname - * is a single "/". - */ - if (resolved_len > 1 && resolved[resolved_len - 1] == '/') - resolved[resolved_len - 1] = '\0'; - return (resolved); + /* + * Remove trailing slash except when the resolved pathname + * is a single "/". + */ + if (resolved_len > 1 && resolved[resolved_len - 1] == '/') + resolved[resolved_len - 1] = '\0'; + return (resolved); err: - if (mem_allocated) - free(resolved); - return (NULL); + if (mem_allocated) free(resolved); + return (NULL); } -static int -int_vasprintf (result, format, args) - char **result; - const char *format; - va_list *args; +static int int_vasprintf(result, format, args) char **result; +const char *format; +va_list *args; { - const char *p = format; - /* Add one to make sure that it is never zero, which might cause malloc - to return NULL. */ - int total_width = strlen (format) + 1; - va_list ap; +const char *p = format; +/* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ +int total_width = strlen(format) + 1; +va_list ap; - memcpy ((void*) &ap, (void*) args, sizeof (va_list)); +memcpy((void *)&ap, (void *)args, sizeof(va_list)); - while (*p != '\0') - { - if (*p++ == '%') - { - while (strchr ("-+ #0", *p)) +while (*p != '\0') { + if (*p++ == '%') { + while (strchr("-+ #0", *p)) ++p; + if (*p == '*') { ++p; - if (*p == '*') - { - ++p; - total_width += abs (va_arg (ap, int)); - } - else - total_width += strtoul (p, (char**)&p, 10); - if (*p == '.') - { - ++p; - if (*p == '*') - { - ++p; - total_width += abs (va_arg (ap, int)); - } - else - total_width += strtoul (p, (char**)&p, 10); - } - while (strchr ("hlL", *p)) + total_width += abs(va_arg(ap, int)); + } else + total_width += strtoul(p, (char **)&p, 10); + if (*p == '.') { ++p; - /* Should be big enough for any format specifier except %s and floats. */ - total_width += 30; - switch (*p) - { + if (*p == '*') { + ++p; + total_width += abs(va_arg(ap, int)); + } else + total_width += strtoul(p, (char **)&p, 10); + } + while (strchr("hlL", *p)) ++p; + /* Should be big enough for any format specifier except %s and floats. */ + total_width += 30; + switch (*p) { case 'd': case 'i': case 'o': @@ -241,77 +222,302 @@ int_vasprintf (result, format, args) case 'x': case 'X': case 'c': - (void) va_arg (ap, int); - break; + (void)va_arg(ap, int); + break; case 'f': case 'e': case 'E': case 'g': case 'G': - (void) va_arg (ap, double); - /* Since an ieee double can have an exponent of 307, we'll - make the buffer wide enough to cover the gross case. */ - total_width += 307; - break; + (void)va_arg(ap, double); + /* Since an ieee double can have an exponent of 307, we'll + make the buffer wide enough to cover the gross case. */ + total_width += 307; + break; case 's': - total_width += strlen (va_arg (ap, char *)); - break; + total_width += strlen(va_arg(ap, char *)); + break; case 'p': case 'n': - (void) va_arg (ap, char *); - break; - } + (void)va_arg(ap, char *); + break; } } +} #ifdef TEST - global_total_width = total_width; +global_total_width = total_width; #endif - *result = malloc (total_width); - if (*result != NULL) - return vsprintf (*result, format, *args); - else - return 0; +*result = malloc(total_width); +if (*result != NULL) +return vsprintf(*result, format, *args); +else +return 0; } -int -vasprintf (result, format, args) - char **result; - const char *format; -#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) - _BSD_VA_LIST_ args; +int vasprintf(result, format, args) char **result; +const char *format; +#if defined(_BSD_VA_LIST_) && defined(__FreeBSD__) +_BSD_VA_LIST_ args; #else - va_list args; +va_list args; #endif -{ - return int_vasprintf (result, format, &args); -} +{ return int_vasprintf(result, format, &args); } -int -vsnprintf (char *s, size_t n, const char *format, va_list ap) -{ - char *buf = 0; - int result = vasprintf (&buf, format, ap); +int vsnprintf(char *s, size_t n, const char *format, va_list ap) { + char *buf = 0; + int result = vasprintf(&buf, format, ap); - if (!buf) - return -1; - if (result < 0) - { - free (buf); - return -1; + if (!buf) return -1; + if (result < 0) { + free(buf); + return -1; } - result = strlen (buf); - if (n > 0) - { - if ((long) n > result) - memcpy (s, buf, result+1); - else - { - memcpy (s, buf, n-1); - s[n - 1] = 0; + result = strlen(buf); + if (n > 0) { + if ((long)n > result) + memcpy(s, buf, result + 1); + else { + memcpy(s, buf, n - 1); + s[n - 1] = 0; } } - free (buf); - return result; + free(buf); + return result; } #endif + +#include + +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +/* + * PUBLIC: #ifndef HAVE_SNPRINTF + * PUBLIC: int snprintf __P((char *, size_t, const char *, ...)); + * PUBLIC: #endif + */ +int +snprintf(char *str, size_t n, const char *fmt, ...) +{ + va_list ap; + int rval; + va_start(ap, fmt); + rval = vsprintf(str, fmt, ap); + va_end(ap); + return (rval); +} + +/* + * Convert a string to a quad integer. + */ +long long strtoq(const char *nptr, char **endptr, int base) { + return strtoll(nptr, endptr, base); +} + +/* + * Convert a string to an unsigned quad integer. + */ +unsigned long long strtouq(const char *nptr, char **endptr, int base) { + return strtoull(nptr, endptr, base); +} + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif + +const float _strtof_powersOf10_[] = +{ // Table giving binary powers of 10. Entry + 10.0f, // is 10^2^i. Used to convert decimal + 100.0f, // exponents into floating-point numbers. + 1.0e4f, 1.0e8f, 1.0e16f, 1.0e32f}; + +/* + *---------------------------------------------------------------------- + * + * strtof -- + * + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Results: + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +float strtof(const char *string, char **endPtr) { + int sign, expSign = FALSE; + float fraction, dblExp; + const float *d; + const char *p; + int c; + int exp = 0; + int fracExp = 0; + int mantSize; + int decPt; + const char *pExp; + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + decPt = -1; + for (mantSize = 0;; mantSize += 1) { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect tahe value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for (; mantSize > 9; mantSize -= 1) { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10 * frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10 * frac2 + (c - '0'); + } + fraction = (1.0e9f * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + const int maxExponent = 38; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ + + if (exp > maxExponent) { + exp = maxExponent; + } + dblExp = 1.0f; + + for (d = _strtof_powersOf10_; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *)p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/toolchain-powerpc.cmake b/toolchain-powerpc.cmake new file mode 100644 index 0000000..bdb9c90 --- /dev/null +++ b/toolchain-powerpc.cmake @@ -0,0 +1,39 @@ +set(CMAKE_SYSTEM_NAME "Generic") +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR powerpc-eabi) + +set(DEVKITPRO $ENV{DEVKITPRO}) +set(DEVKITPPC $ENV{DEVKITPPC}) +set(GEKKO true) + +if(NOT DEVKITPPC) + message(FATAL_ERROR "Please set DEVKITPPC in your environment") +endif() + +if(NOT DEVKITPRO) + message(FATAL_ERROR "Please set DEVKITPRO in your environment") +endif() + +if(NOT LIBOGCDIR) + message(STATUS "LIBOGCDIR not set, using default") + set(LIBOGCDIR ${DEVKITPRO}/libogc) +endif() + +if(WIN32) + set(CMAKE_C_COMPILER ${DEVKITPPC}/bin/powerpc-eabi-gcc.exe) + set(CMAKE_CXX_COMPILER ${DEVKITPPC}/bin/powerpc-eabi-g++.exe) +else() + set(CMAKE_C_COMPILER ${DEVKITPPC}/bin/powerpc-eabi-gcc) + set(CMAKE_CXX_COMPILER ${DEVKITPPC}/bin/powerpc-eabi-g++) +endif() + +set(MACHDEP "-DGEKKO -mrvl -mcpu=750 -meabi -mhard-float") + +set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} ${MACHDEP}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MACHDEP}") +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(CMAKE_FIND_ROOT_PATH ${DEVKITPPC}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)