Windows compatibility (#207)

* incorrect environment detection fixed
* use %zu instead of %ld for size_t
* fix rounding in integer division
* fix compiler error on Windows
* implement missed functions
* make linker available if MinGW environment is used
* make linker available under MSYS2 Clang64 and MSYS2 MinGW64
This commit is contained in:
kvk1920
2021-07-13 13:59:55 +03:00
committed by GitHub
parent 9a6d8d7657
commit 050382b68e
8 changed files with 157 additions and 8 deletions

View File

@@ -1,5 +1,7 @@
#include "compiler_internal.h"
#include <llvm/Config/llvm-config.h> // for LLVM_VERSION_STRING
extern bool llvm_link_elf(const char **args, int arg_count, const char** error_string);
extern bool llvm_link_macho(const char **args, int arg_count, const char** error_string);
extern bool llvm_link_coff(const char **args, int arg_count, const char** error_string);
@@ -14,6 +16,51 @@ static void add_files(const char ***args, const char **files_to_link, unsigned f
}
}
static const char *join_strings(const char **args, unsigned count)
{
char *res = "";
for (unsigned i = 0; i < count; ++i)
{
res = strcat_arena(res, args[i]);
}
return res;
}
static void prepare_msys2_linker_flags(const char ***args, const char **files_to_link, unsigned file_count)
{
const char *root = getenv("MSYSTEM_PREFIX");
#define add_arg(opt) vec_add(*args, opt)
add_arg("-m");
add_arg("i386pep");
add_arg("-Bdynamic");
add_arg(join_strings((const char *[]){root, "\\x86_64-w64-mingw32\\lib\\crt2.o"}, 2));
add_arg(join_strings((const char *[]){root, "\\x86_64-w64-mingw32\\lib\\crtbegin.o"}, 2));
add_arg(join_strings((const char *[]){"-L", root, "\\x86_64-w64-mingw32\\lib"}, 3));
add_arg(join_strings((const char *[]){"-L", root, "\\lib"}, 3));
add_arg(join_strings((const char *[]){"-L", root, "\\x86_64-w64-mingw32\\sys-root\\mingw\\lib"}, 3));
add_arg(join_strings((const char *[]){"-L", root, "\\lib\\clang\\", LLVM_VERSION_STRING, "\\lib\\windows"}, 5));
add_files(args, files_to_link, file_count);
add_arg("-lmingw32");
add_arg(join_strings((const char *[]){root, "\\lib\\clang\\", LLVM_VERSION_STRING, "\\lib\\windows\\libclang_rt.builtins-x86_64.a"}, 4));
add_arg("-lunwind");
add_arg("-lmoldname");
add_arg("-lmingwex");
add_arg("-lmsvcrt");
add_arg("-ladvapi32");
add_arg("-lshell32");
add_arg("-luser32");
add_arg("-lkernel32");
add_arg("-lmingw32");
add_arg(join_strings((const char *[]){root, "\\lib\\clang\\", LLVM_VERSION_STRING, "\\lib\\windows\\libclang_rt.builtins-x86_64.a"}, 4));
add_arg("-lunwind");
add_arg("-lmoldname");
add_arg("-lmingwex");
add_arg("-lmsvcrt");
add_arg("-lkernel32");
add_arg(join_strings((const char *[]){root, "\\x86_64-w64-mingw32\\lib\\crtend.o"}, 2));
#undef add_arg
}
static bool link_exe(const char *output_file, const char **files_to_link, unsigned file_count)
{
const char **args = NULL;
@@ -24,7 +71,20 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
switch (platform_target.os)
{
case OS_TYPE_WIN32:
return false;
// TODO: properly detect if llvm-lld is available
// TODO: check if running inside MSYS2, it could be done via getting MSYSTEM environment variable
// https://stackoverflow.com/questions/65527286/how-to-check-if-my-program-is-running-on-mingwor-msys-shell-or-on-cmd
if (!platform_target.x64.is_mingw64) return false;
if (NULL == getenv("MSYSTEM")) return false;
if (!strcmp(getenv("MSYSTEM"), "CLANG64") || !strcmp(getenv("MSYSTEM"), "MINGW64"))
{
prepare_msys2_linker_flags(&args, files_to_link, file_count);
}
else
{
return false;
}
break;
case OS_TYPE_MACOSX:
add_files(&args, files_to_link, file_count);
vec_add(args, "-lSystem");
@@ -110,7 +170,7 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
switch (platform_target.object_format)
{
case OBJ_FORMAT_COFF:
success = llvm_link_coff(args, (int)vec_size(args), &error);
success = (platform_target.x64.is_mingw64 ? llvm_link_mingw : llvm_link_coff)(args, (int)vec_size(args), &error);
break;
case OBJ_FORMAT_ELF:
success = llvm_link_elf(args, (int)vec_size(args), &error);

View File

@@ -571,7 +571,7 @@ static OsType os_from_llvm_string(StringSlice os_string)
static VendorType vendor_from_llvm_string(StringSlice slice)
{
#define STRCASE(_str, _vendor) if (slicestrcmp(slice, _str) == 0) return _vendor;
#define STRCASE(_str, _vendor) if (slicestrcmp(slice, _str)) return _vendor;
STRCASE("apple", VENDOR_APPLE)
STRCASE("pc", VENDOR_PC)
STRCASE("scei", VENDOR_SCEI)

View File

@@ -13,6 +13,10 @@
#include <errno.h>
#include "whereami.h"
#if PLATFORM_WINDOWS
#include <windows.h>
#endif
const char* expand_path(const char* path)
{
@@ -186,7 +190,14 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi
// Doesn't end with .c3
if (strncmp(&ent->d_name[namelen - 3], ".c3", 3) != 0)
{
if (ent->d_type == DT_DIR && ent->d_name[0] != '.' && recursive)
bool is_directory;
#if PLATFORM_WINDOWS
struct stat st;
is_directory = stat(ent->d_name, &st) == 0 && S_ISDIR(st.st_mode);
#else
is_directory = ent->d_type == DT_DIR; // is it POSIX-compliant? As
#endif
if (is_directory && ent->d_name[0] != '.' && recursive)
{
char *new_path = strndup(ent->d_name, namelen);
file_add_wildcard_files(files, new_path, recursive);
@@ -201,4 +212,20 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi
vec_add(*files, name);
}
closedir(dir);
}
}
#if PLATFORM_WINDOWS
char *realpath(const char *path, char *const resolved_path)
{
char *result = NULL == resolved_path ? calloc(PATH_MAX + 1, 1) : resolved_path;
if (NULL == result) return NULL;
if (!GetFullPathNameA(path, MAX_PATH, result, NULL))
{
if (NULL == resolved_path) free(result);
return NULL;
}
return result;
}
#endif

View File

@@ -6,6 +6,10 @@
#include "common.h"
#if PLATFORM_WINDOWS
#include "direct.h"
#endif
typedef struct Task_
{
void (*task)(void *arg);
@@ -434,3 +438,18 @@ static inline StringSlice strtoslice(const char *data)
typeof(_a) __a__ = (_a); \
typeof(_b) __b__ = (_b); \
__a__ < __b__ ? __a__ : __b__; })
// Windows-specific code
#if PLATFORM_WINDOWS
int asprintf(char **strp, const char *fmt, ...);
int vasprintf(char **strp, const char *fmt, va_list ap);
char *strndup(const char *s, size_t len);
char *realpath(const char *path, char *resolved_path);
#define mkdir(name, unused) _mkdir(name)
#endif

View File

@@ -31,7 +31,7 @@ void *malloc_arena(size_t mem)
void print_arena_status(void)
{
printf("-- ARENA INFO -- \n");
printf(" * Memory used: %ld Kb\n", arena.allocated / 1024);
printf(" * Memory used: %zu Kb\n", arena.allocated / 1024);
printf(" * Allocations: %d\n", allocations_done);
}

View File

@@ -59,4 +59,44 @@ char *strcat_arena(const char *a, const char *b)
memcpy(buffer + a_len, b, b_len);
buffer[a_len + b_len] = '\0';
return buffer;
}
}
#if PLATFORM_WINDOWS
int asprintf(char **strp, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int res = vasprintf(strp, fmt, args);
va_end(args);
return res;
}
int vasnprintf(char **strp, const char *fmt, va_list args)
{
va_list args_copy;
va_copy(args_copy, args);
int res = vsprintf(NULL, fmt, args);
if (res < 0) goto END;
char *buf = calloc(res + 1, 1);
if (NULL == buf) goto END;
sprintf(buf, fmt, args_copy); // this can't fail, right?
*strp = buf;
END:
va_end(args_copy);
return res;
}
char *strndup(const char *s, size_t n)
{
n = strnlen(s, n);
char *t = calloc(n + 1, 1);
if (NULL != t)
{
memcpy(t, s, n);
t[n] = '\0';
}
return t;
}
#endif

View File

@@ -42,7 +42,7 @@ static inline void* mmap_allocate(Vmem *vmem, size_t to_allocate)
size_t allocated_after = to_allocate + vmem->allocated;
#if PLATFORM_WINDOWS
size_t blocks_committed = vmem->committed / COMMIT_PAGE_SIZE;
size_t end_block = (allocated_after) / COMMIT_PAGE_SIZE;
size_t end_block = (allocated_after + COMMIT_PAGE_SIZE - 1) / COMMIT_PAGE_SIZE; // round up
size_t blocks_to_allocate = end_block - blocks_committed;
if (blocks_to_allocate > 0)
{

View File

@@ -65,6 +65,9 @@ static bool llvm_link(ObjFormat format, const char **args, int arg_count, const
case COFF:
if (lld::coff::link(arg_vector, false, output, output_err)) return true;
break;
case MINGW:
if (lld::mingw::link(arg_vector, false, output, output_err)) return true;
break;
default:
exit(-1);
}