mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user