Fix gc/wii build

This commit is contained in:
Phillip Stephens 2015-10-16 01:07:54 -07:00
parent 340588db62
commit 1c0c44938e
9 changed files with 523 additions and 256 deletions

View File

@ -25,11 +25,12 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif() endif()
if(WIN32) if(WIN32)
list(APPEND CORE_EXTRA src/win32_largefilewrapper.c) list(APPEND CORE_EXTRA src/win32_largefilewrapper.c include/win32_largefilewrapper.h)
elseif(APPLE) elseif(APPLE OR GEKKO)
list(APPEND CORE_EXTRA src/osx_largefilewrapper.c) list(APPEND CORE_EXTRA src/osx_largefilewrapper.c include/osx_largefilewrapper.h)
elseif(GEKKO) if(GEKKO)
list(APPEND CORE_EXTRA src/gekko_support.c) list(APPEND CORE_EXTRA src/gekko_support.c include/gekko_support.h)
endif()
endif() endif()
add_library(AthenaCore add_library(AthenaCore
@ -68,7 +69,6 @@ add_library(AthenaCore
include/LZ77/LZType11.hpp include/LZ77/LZType11.hpp
include/Athena/FileInfo.hpp include/Athena/FileInfo.hpp
include/Athena/Dir.hpp include/Athena/Dir.hpp
include/gekko_support.h
include/Athena/DNA.hpp include/Athena/DNA.hpp
include/Athena/DNAYaml.hpp include/Athena/DNAYaml.hpp
include/yaml.h include/yaml.h
@ -117,7 +117,7 @@ add_library(AthenaWiiSave EXCLUDE_FROM_ALL
include/md5.h include/md5.h
include/sha1.h include/sha1.h
) )
if(NOT MSVC) if(NOT MSVC AND NOT GEKKO)
set_source_files_properties(src/aes.cpp PROPERTIES COMPILE_FLAGS -maes) set_source_files_properties(src/aes.cpp PROPERTIES COMPILE_FLAGS -maes)
endif() endif()
@ -227,7 +227,9 @@ install(EXPORT AthenaTargets DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT Athena)
# atdna import # # atdna import #
################ ################
if(NOT GEKKO)
add_subdirectory(atdna) add_subdirectory(atdna)
endif()
######### #########
# CPack # # CPack #

View File

@ -7,6 +7,10 @@
* Any changes to the types or namespacing must be reflected in 'atdna/main.cpp' * Any changes to the types or namespacing must be reflected in 'atdna/main.cpp'
*/ */
#ifdef GEKKO
#include <stdlib.h>
#include <limits.h>
#endif
#include <string.h> #include <string.h>
#include <yaml.h> #include <yaml.h>
#include <utf8proc.h> #include <utf8proc.h>

View File

@ -4,6 +4,9 @@
#ifdef GEKKO #ifdef GEKKO
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -12,7 +15,14 @@ char *
realpath(const char *path, char *resolved); realpath(const char *path, char *resolved);
int int
vsnprintf (char *s, size_t n, const char *format, va_list ap); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,7 +1,7 @@
#ifndef OSX_LARGEFILEWRAPPER_H #ifndef OSX_LARGEFILEWRAPPER_H
#define OSX_LARGEFILEWRAPPER_H #define OSX_LARGEFILEWRAPPER_H
#if defined(__APPLE__) #if defined(__APPLE__) || defined(GEKKO)
#include <stdio.h> #include <stdio.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View File

@ -4,6 +4,9 @@
#include "win32_largefilewrapper.h" #include "win32_largefilewrapper.h"
#elif __APPLE__ #elif __APPLE__
#include "osx_largefilewrapper.h" #include "osx_largefilewrapper.h"
#elif GEKKO
#include "gekko_support.h"
#include "osx_largefilewrapper.h"
#endif #endif
namespace Athena namespace Athena

View File

@ -4,6 +4,9 @@
#include "win32_largefilewrapper.h" #include "win32_largefilewrapper.h"
#elif __APPLE__ #elif __APPLE__
#include "osx_largefilewrapper.h" #include "osx_largefilewrapper.h"
#elif GEKKO
#include "gekko_support.h"
#include "osx_largefilewrapper.h"
#endif #endif
namespace Athena namespace Athena

View File

@ -3,7 +3,7 @@
#include <string.h> #include <string.h>
#if _WIN32 #if _WIN32
#include <intrin.h> #include <intrin.h>
#else #elif !GEKKO
#include <cpuid.h> #include <cpuid.h>
#endif #endif

View File

@ -21,219 +21,200 @@
* components. Returns (resolved) on success, or (NULL) on failure, * components. Returns (resolved) on success, or (NULL) on failure,
* in which case the path which caused trouble is left in (resolved). * in which case the path which caused trouble is left in (resolved).
*/ */
char * char *realpath(const char *path, char *resolved) {
realpath(const char *path, char *resolved) struct stat sb;
{ char *p, *q, *s;
struct stat sb; size_t left_len, resolved_len;
char *p, *q, *s; unsigned symlinks;
size_t left_len, resolved_len; int serrno, slen, mem_allocated;
unsigned symlinks; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
int serrno, slen, mem_allocated;
char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
if (path[0] == '\0') { if (path[0] == '\0') {
errno = ENOENT; errno = ENOENT;
return (NULL); return (NULL);
} }
serrno = errno; serrno = errno;
if (resolved == NULL) { if (resolved == NULL) {
resolved = malloc(PATH_MAX); resolved = malloc(PATH_MAX);
if (resolved == NULL) if (resolved == NULL) return (NULL);
return (NULL); mem_allocated = 1;
mem_allocated = 1; } else
} else mem_allocated = 0;
mem_allocated = 0;
symlinks = 0; symlinks = 0;
if (path[0] == '/') { if (path[0] == '/') {
resolved[0] = '/'; resolved[0] = '/';
resolved[1] = '\0'; resolved[1] = '\0';
if (path[1] == '\0') if (path[1] == '\0') return (resolved);
return (resolved); resolved_len = 1;
resolved_len = 1; left_len = strlcpy(left, path + 1, sizeof(left));
left_len = strlcpy(left, path + 1, sizeof(left)); } else {
} else { if (getcwd(resolved, PATH_MAX) == NULL) {
if (getcwd(resolved, PATH_MAX) == NULL) { if (mem_allocated)
if (mem_allocated) free(resolved);
free(resolved); else
else strlcpy(resolved, ".", PATH_MAX);
strlcpy(resolved, ".", PATH_MAX); return (NULL);
return (NULL); }
} resolved_len = strlen(resolved);
resolved_len = strlen(resolved); left_len = strlcpy(left, path, sizeof(left));
left_len = strlcpy(left, path, sizeof(left)); }
} if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { errno = ENAMETOOLONG;
errno = ENAMETOOLONG; goto err;
goto err; }
}
/* /*
* Iterate over path components in `left'. * Iterate over path components in `left'.
*/ */
while (left_len != 0) { while (left_len != 0) {
/* /*
* Extract the next path component and adjust `left' * Extract the next path component and adjust `left'
* and its length. * and its length.
*/ */
p = strchr(left, '/'); p = strchr(left, '/');
s = p ? p : left + left_len; s = p ? p : left + left_len;
if (s - left >= sizeof(next_token)) { if (s - left >= sizeof(next_token)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err; goto err;
} }
memcpy(next_token, left, s - left); memcpy(next_token, left, s - left);
next_token[s - left] = '\0'; next_token[s - left] = '\0';
left_len -= s - left; left_len -= s - left;
if (p != NULL) if (p != NULL) memmove(left, s + 1, left_len + 1);
memmove(left, s + 1, left_len + 1); if (resolved[resolved_len - 1] != '/') {
if (resolved[resolved_len - 1] != '/') { if (resolved_len + 1 >= PATH_MAX) {
if (resolved_len + 1 >= PATH_MAX) { errno = ENAMETOOLONG;
errno = ENAMETOOLONG; goto err;
goto err; }
} resolved[resolved_len++] = '/';
resolved[resolved_len++] = '/'; resolved[resolved_len] = '\0';
resolved[resolved_len] = '\0'; }
} if (next_token[0] == '\0')
if (next_token[0] == '\0') continue;
continue; else if (strcmp(next_token, ".") == 0)
else if (strcmp(next_token, ".") == 0) continue;
continue; else if (strcmp(next_token, "..") == 0) {
else if (strcmp(next_token, "..") == 0) { /*
/* * Strip the last path component except when we have
* Strip the last path component except when we have * single "/"
* single "/" */
*/ if (resolved_len > 1) {
if (resolved_len > 1) { resolved[resolved_len - 1] = '\0';
resolved[resolved_len - 1] = '\0'; q = strrchr(resolved, '/') + 1;
q = strrchr(resolved, '/') + 1; *q = '\0';
*q = '\0'; resolved_len = q - resolved;
resolved_len = q - resolved; }
} continue;
continue; }
}
/* /*
* Append the next path component and lstat() it. If * Append the next path component and lstat() it. If
* lstat() fails we still can return successfully if * lstat() fails we still can return successfully if
* there are no more path components left. * there are no more path components left.
*/ */
resolved_len = strlcat(resolved, next_token, PATH_MAX); resolved_len = strlcat(resolved, next_token, PATH_MAX);
if (resolved_len >= PATH_MAX) { if (resolved_len >= PATH_MAX) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err; goto err;
} }
if (lstat(resolved, &sb) != 0) { if (lstat(resolved, &sb) != 0) {
if (errno == ENOENT && p == NULL) { if (errno == ENOENT && p == NULL) {
errno = serrno; errno = serrno;
return (resolved); return (resolved);
} }
goto err; goto err;
} }
if (S_ISLNK(sb.st_mode)) { if (S_ISLNK(sb.st_mode)) {
if (symlinks++ > SYMLOOP_MAX) { if (symlinks++ > SYMLOOP_MAX) {
errno = ELOOP; errno = ELOOP;
goto err; goto err;
} }
slen = readlink(resolved, symlink, sizeof(symlink) - 1); slen = readlink(resolved, symlink, sizeof(symlink) - 1);
if (slen < 0) if (slen < 0) goto err;
goto err; symlink[slen] = '\0';
symlink[slen] = '\0'; if (symlink[0] == '/') {
if (symlink[0] == '/') { resolved[1] = 0;
resolved[1] = 0; resolved_len = 1;
resolved_len = 1; } else if (resolved_len > 1) {
} else if (resolved_len > 1) { /* Strip the last path component. */
/* Strip the last path component. */ resolved[resolved_len - 1] = '\0';
resolved[resolved_len - 1] = '\0'; q = strrchr(resolved, '/') + 1;
q = strrchr(resolved, '/') + 1; *q = '\0';
*q = '\0'; resolved_len = q - resolved;
resolved_len = q - resolved; }
}
/* /*
* If there are any path components left, then * If there are any path components left, then
* append them to symlink. The result is placed * append them to symlink. The result is placed
* in `left'. * in `left'.
*/ */
if (p != NULL) { if (p != NULL) {
if (symlink[slen - 1] != '/') { if (symlink[slen - 1] != '/') {
if (slen + 1 >= sizeof(symlink)) { if (slen + 1 >= sizeof(symlink)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err; goto err;
} }
symlink[slen] = '/'; symlink[slen] = '/';
symlink[slen + 1] = 0; symlink[slen + 1] = 0;
} }
left_len = strlcat(symlink, left, sizeof(symlink)); left_len = strlcat(symlink, left, sizeof(symlink));
if (left_len >= sizeof(left)) { if (left_len >= sizeof(left)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
goto err; goto err;
} }
} }
left_len = strlcpy(left, symlink, sizeof(left)); left_len = strlcpy(left, symlink, sizeof(left));
} }
} }
/* /*
* Remove trailing slash except when the resolved pathname * Remove trailing slash except when the resolved pathname
* is a single "/". * is a single "/".
*/ */
if (resolved_len > 1 && resolved[resolved_len - 1] == '/') if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
resolved[resolved_len - 1] = '\0'; resolved[resolved_len - 1] = '\0';
return (resolved); return (resolved);
err: err:
if (mem_allocated) if (mem_allocated) free(resolved);
free(resolved); return (NULL);
return (NULL);
} }
static int static int int_vasprintf(result, format, args) char **result;
int_vasprintf (result, format, args) const char *format;
char **result; va_list *args;
const char *format;
va_list *args;
{ {
const char *p = format; const char *p = format;
/* Add one to make sure that it is never zero, which might cause malloc /* Add one to make sure that it is never zero, which might cause malloc
to return NULL. */ to return NULL. */
int total_width = strlen (format) + 1; int total_width = strlen(format) + 1;
va_list ap; va_list ap;
memcpy ((void*) &ap, (void*) args, sizeof (va_list)); memcpy((void *)&ap, (void *)args, sizeof(va_list));
while (*p != '\0') while (*p != '\0') {
{ if (*p++ == '%') {
if (*p++ == '%') while (strchr("-+ #0", *p)) ++p;
{ if (*p == '*') {
while (strchr ("-+ #0", *p))
++p; ++p;
if (*p == '*') total_width += abs(va_arg(ap, int));
{ } else
++p; total_width += strtoul(p, (char **)&p, 10);
total_width += abs (va_arg (ap, int)); if (*p == '.') {
}
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))
++p; ++p;
/* Should be big enough for any format specifier except %s and floats. */ if (*p == '*') {
total_width += 30; ++p;
switch (*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 'd':
case 'i': case 'i':
case 'o': case 'o':
@ -241,77 +222,302 @@ int_vasprintf (result, format, args)
case 'x': case 'x':
case 'X': case 'X':
case 'c': case 'c':
(void) va_arg (ap, int); (void)va_arg(ap, int);
break; break;
case 'f': case 'f':
case 'e': case 'e':
case 'E': case 'E':
case 'g': case 'g':
case 'G': case 'G':
(void) va_arg (ap, double); (void)va_arg(ap, double);
/* Since an ieee double can have an exponent of 307, we'll /* Since an ieee double can have an exponent of 307, we'll
make the buffer wide enough to cover the gross case. */ make the buffer wide enough to cover the gross case. */
total_width += 307; total_width += 307;
break; break;
case 's': case 's':
total_width += strlen (va_arg (ap, char *)); total_width += strlen(va_arg(ap, char *));
break; break;
case 'p': case 'p':
case 'n': case 'n':
(void) va_arg (ap, char *); (void)va_arg(ap, char *);
break; break;
}
} }
} }
}
#ifdef TEST #ifdef TEST
global_total_width = total_width; global_total_width = total_width;
#endif #endif
*result = malloc (total_width); *result = malloc(total_width);
if (*result != NULL) if (*result != NULL)
return vsprintf (*result, format, *args); return vsprintf(*result, format, *args);
else else
return 0; return 0;
} }
int int vasprintf(result, format, args) char **result;
vasprintf (result, format, args) const char *format;
char **result; #if defined(_BSD_VA_LIST_) && defined(__FreeBSD__)
const char *format; _BSD_VA_LIST_ args;
#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
_BSD_VA_LIST_ args;
#else #else
va_list args; va_list args;
#endif #endif
{ { return int_vasprintf(result, format, &args); }
return int_vasprintf (result, format, &args);
}
int int vsnprintf(char *s, size_t n, const char *format, va_list ap) {
vsnprintf (char *s, size_t n, const char *format, va_list ap) char *buf = 0;
{ int result = vasprintf(&buf, format, ap);
char *buf = 0;
int result = vasprintf (&buf, format, ap);
if (!buf) if (!buf) return -1;
return -1; if (result < 0) {
if (result < 0) free(buf);
{ return -1;
free (buf);
return -1;
} }
result = strlen (buf); result = strlen(buf);
if (n > 0) if (n > 0) {
{ if ((long)n > result)
if ((long) n > result) memcpy(s, buf, result + 1);
memcpy (s, buf, result+1); else {
else memcpy(s, buf, n - 1);
{ s[n - 1] = 0;
memcpy (s, buf, n-1);
s[n - 1] = 0;
} }
} }
free (buf); free(buf);
return result; return result;
} }
#endif #endif
#include <sys/types.h>
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#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;
}

39
toolchain-powerpc.cmake Normal file
View File

@ -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)