Skip to content

Commit

Permalink
hax go brr
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli committed Dec 4, 2023
1 parent c8d9474 commit 9bd3958
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
70 changes: 61 additions & 9 deletions self_hosted/paths.jou
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,83 @@ declare _mkdir(path: byte*) -> int # windows
declare mkdir(path: byte*, mode: int) -> int # posix
declare dirname(path: byte*) -> byte*
declare stat(path: byte*, buf: byte[1000]*) -> int # lol
declare popen(command: byte*, type: byte*) -> FILE*
declare pclose(stream: FILE*) -> int
declare _NSGetExecutablePath(buf: byte*, bufsize: int*) -> int


def is_windows() -> bool:
# TODO: this is just weird...
return getenv("OS") != NULL and strstr(getenv("OS"), "Windows") != NULL

# Return a path to the currently running program. Return value must be free()d.
def find_current_executable() -> byte*:
# https://stackoverflow.com/a/3466183
def is_macos() -> bool:
if is_windows():
return False

uname = popen("uname", "r")
if uname == NULL:
return False

output: byte[100]
memset(&output, 0, sizeof(output))
fgets(output, sizeof(output) as int, uname)

pclose(uname)
return starts_with(output, "Darwin")


def _find_current_executable_windows() -> byte*:
buf = NULL
for size = 2L; True; size *= 2:
buf = realloc(buf, size)
memset(buf, 0, size)
ret = GetModuleFileNameA(NULL, buf, size as int)
if ret <= 0:
return NULL # error --> give up
if ret < size:
# buffer is big enough, it fits
return buf

if is_windows():
ret: long = GetModuleFileNameA(NULL, buf, size as int)
else:
ret = readlink("/proc/self/exe", buf, size)
def _find_current_executable_macos() -> byte*:
n = 1
result: byte* = malloc(n)
ret = _NSGetExecutablePath(result, &n) # sets n to desired size
assert ret < 0 # didn't fit
result = realloc(result, n)
ret = _NSGetExecutablePath(result, &n)
assert ret == 0
return result

def _find_current_executable_linux() -> byte*:
buf = NULL
for size = 2L; True; size *= 2:
buf = realloc(buf, size)
memset(buf, 0, size)
ret = readlink("/proc/self/exe", buf, size)
if ret <= 0:
# TODO: include os error message (GetLastError / errno)
fprintf(stderr, "error: cannot locate currently running executable, needed for finding the Jou standard library\n")
exit(1)
return NULL
if ret < size:
# buffer is big enough, it fits
return buf


def find_current_executable() -> byte*:
if is_windows():
result = _find_current_executable_windows()
elif is_macos():
result = _find_current_executable_macos()
else:
result = _find_current_executable_linux()

if result == NULL:
# TODO: include os error message (GetLastError / errno)
fprintf(stderr, "error: cannot locate currently running executable, needed for finding the Jou standard library\n")
exit(1)

return result


def find_installation_directory() -> byte*:
exe = find_current_executable()
result = strdup(dirname(exe))
Expand Down
6 changes: 4 additions & 2 deletions src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,11 @@ static LLVMValueRef codegen_function_or_method_decl(const struct State *st, cons
// make it a definition instead of a declaration so that there are no linker errors.
// Ideally it would be possible to compile some parts of Jou code only for a specific platform.
#ifdef _WIN32
const char *doesnt_exist[] = { "readlink", "mkdir", "popen", "pclose" };
#else
const char *doesnt_exist[] = { "readlink", "mkdir", "popen", "pclose", "_NSGetExecutablePath" };
#elif defined(__APPLE__)
const char *doesnt_exist[] = { "GetModuleFileNameA", "_mkdir" };
#else
const char *doesnt_exist[] = { "GetModuleFileNameA", "_mkdir", "_NSGetExecutablePath" };
#endif
for (unsigned i = 0; i < sizeof doesnt_exist / sizeof doesnt_exist[0]; i++) {
if (!strcmp(fullname, doesnt_exist[i])) {
Expand Down

0 comments on commit 9bd3958

Please sign in to comment.