MSVC compatibility

This commit is contained in:
C34A
2021-09-23 19:12:21 -07:00
committed by Christoffer Lerno
parent b4df56db54
commit 5dea48101f
25 changed files with 1443 additions and 43 deletions

5
.gitignore vendored
View File

@@ -60,3 +60,8 @@ dkms.conf
/resources/y.tab.c /resources/y.tab.c
/resources/y.tab.h /resources/y.tab.h
/bin/ /bin/
#visual studio files
.vs/
.vscode/
out/

View File

@@ -53,18 +53,21 @@ llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR}) file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR})
find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS}) # These don't seem to be reliable on windows.
find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS}) if(UNIX)
find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS}) message(STATUS "using find_library")
find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_ELF NAMES lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_DRIVER NAMES lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_READER_WRITER NAMES lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MACHO NAMES lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_ELF NAMES lldELF.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_YAML NAMES lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_DRIVER NAMES lldDriver.a liblldDriver.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_READER_WRITER NAMES lldReaderWriter.a liblldReaderWriter.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_MACHO NAMES lldMachO.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS})
find_library(LLD_YAML NAMES lldYAML.a liblldYAML.a PATHS ${LLVM_LIBRARY_DIRS})
set(lld_libs set(lld_libs
${LLD_COFF} ${LLD_COFF}
${LLD_COMMON} ${LLD_COMMON}
${LLD_WASM} ${LLD_WASM}
@@ -76,6 +79,8 @@ set(lld_libs
${LLD_YAML} ${LLD_YAML}
${LLD_CORE} ${LLD_CORE}
) )
message(STATUS "linking to llvm libs ${llvm_libs} ${lld_libs}")
endif()
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp) add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
add_executable(c3c add_executable(c3c
@@ -107,6 +112,7 @@ add_executable(c3c
src/compiler/module.c src/compiler/module.c
src/compiler/llvm_codegen.c src/compiler/llvm_codegen.c
src/utils/stringutils.c src/utils/stringutils.c
src/utils/find_msvc.c
src/compiler/dwarf.h src/compiler/dwarf.h
src/compiler/copying.c src/compiler/copying.c
src/compiler/llvm_codegen_stmt.c src/compiler/llvm_codegen_stmt.c
@@ -145,9 +151,11 @@ add_executable(c3c
src/compiler/llvm_codegen_c_abi_riscv.c src/compiler/llvm_codegen_c_abi_riscv.c
src/compiler/llvm_codegen_c_abi_wasm.c) src/compiler/llvm_codegen_c_abi_wasm.c)
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) message(STATUS "using gcc/clang warning switches")
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
endif()
target_include_directories(c3c PRIVATE target_include_directories(c3c PRIVATE
"${CMAKE_SOURCE_DIR}/src/") "${CMAKE_SOURCE_DIR}/src/")
@@ -158,9 +166,18 @@ target_include_directories(c3c_wrappers PRIVATE
message(STATUS "Found LLD ${lld_libs}") message(STATUS "Found LLD ${lld_libs}")
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs}) if(UNIX)
#target_link_libraries(c3c m ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML) message(STATUS "adding unix link params")
target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs}) target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs})
else()
# todo: maybe get this from llvm-config somehow? it should be in LLVM_DIR\..\..\..\bin I think.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -LIBPATH:C:\\llvm\\llvm\\build\\Release\\lib") # needed for lldCommon.lib
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -LIBPATH:${LLVM_LIBPATH}") # This doesn't seem to work for some reason
message(STATUS "${LLVM_LIBPATH}")
target_link_libraries(c3c debug ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML)
target_link_libraries(c3c optimized ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML)
endif()
if (WIN32) if (WIN32)
if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILE_ID STREQUAL "GNU") if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILE_ID STREQUAL "GNU")

15
CMakeSettings.json Normal file
View File

@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "build",
"generator": "Ninja",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DLLVM_DIR=C:\\llvm\\llvm\\build\\lib\\cmake\\llvm -DCMAKE_CXX_FLAGS:STRING=\"${CMAKE_CXX_FLAGS} /J\"",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
}
]
}

View File

@@ -6,7 +6,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>
#endif
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <utils/lib.h> #include <utils/lib.h>

View File

@@ -1,8 +1,11 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved. // Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0 // Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#ifndef _MSC_VER
#include <dirent.h> #include <dirent.h>
#else
#include "utils/dirent.h"
#endif
#include "build_internal.h" #include "build_internal.h"
#include "build_options.h" #include "build_options.h"
@@ -93,6 +96,16 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{ {
target->arch_os_target = options->arch_os_target_override; target->arch_os_target = options->arch_os_target_override;
} }
#ifndef _MSC_VER
#define _MSC_VER 0
#endif
else if (_MSC_VER)
{
// The current handling of ARCH_OS_TARGET_DEFAULT works on unix, but not on windows.
// to deal with this, simply default to x64-windows (unless using mingw).
// ARCH_OS_TARGET_DEFAULT could be handled in a more cross-platform manner later on.
target->arch_os_target = X64_WINDOWS;
}
if (options->pie != PIE_DEFAULT) target->pie = options->pie; if (options->pie != PIE_DEFAULT) target->pie = options->pie;
if (options->pic != PIC_DEFAULT) target->pic = options->pic; if (options->pic != PIC_DEFAULT) target->pic = options->pic;

View File

@@ -6,7 +6,9 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>
#endif
#include <string.h> #include <string.h>
#include "project_creation.h" #include "project_creation.h"
#include "build_options.h" #include "build_options.h"

View File

@@ -4,7 +4,9 @@
#include "compiler_internal.h" #include "compiler_internal.h"
#include "parser_internal.h" #include "parser_internal.h"
#ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>
#endif
#define MAX_OUTPUT_FILES 1000000 #define MAX_OUTPUT_FILES 1000000
#define MAX_MODULES 100000 #define MAX_MODULES 100000
@@ -483,7 +485,7 @@ static void target_expand_source_names(BuildTarget *target)
void compile_target(BuildOptions *options) void compile_target(BuildOptions *options)
{ {
init_default_build_target(&active_target, options, "a.out"); init_default_build_target(&active_target, options, DEFAULT_EXE);
compile(); compile();
} }

View File

@@ -30,6 +30,13 @@ typedef int32_t ScopeId;
#define DEFAULT_EXE "a.out" #define DEFAULT_EXE "a.out"
#endif #endif
#if PLATFORM_WINDOWS
#define DEFAULT_OBJ_FILE_EXT ".obj"
#else
#define DEFAULT_OBJ_FILE_EXT ".o"
#endif
typedef uint32_t SourceLoc; typedef uint32_t SourceLoc;
typedef struct typedef struct
{ {
@@ -554,9 +561,9 @@ typedef struct Decl_
SourceSpan span; SourceSpan span;
const char *external_name; const char *external_name;
Ast *docs; Ast *docs;
DeclKind decl_kind : 6; DeclKind decl_kind : 7;
Visibility visibility : 2; Visibility visibility : 3;
ResolveStatus resolve_status : 2; ResolveStatus resolve_status : 3;
bool is_packed : 1; bool is_packed : 1;
bool is_opaque : 1; bool is_opaque : 1;
bool needs_additional_pad : 1; bool needs_additional_pad : 1;

View File

@@ -295,7 +295,7 @@ typedef enum
TYPE_INFO_POINTER, TYPE_INFO_POINTER,
} TypeInfoKind; } TypeInfoKind;
typedef enum typedef enum
{ {
TOKEN_INVALID_TOKEN = 0, TOKEN_INVALID_TOKEN = 0,

View File

@@ -2,6 +2,10 @@
#include <llvm/Config/llvm-config.h> // for LLVM_VERSION_STRING #include <llvm/Config/llvm-config.h> // for LLVM_VERSION_STRING
#ifdef PLATFORM_WINDOWS
#include "utils/find_msvc.h"
#endif
extern bool llvm_link_elf(const char **args, int arg_count, const char** error_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_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); extern bool llvm_link_coff(const char **args, int arg_count, const char** error_string);
@@ -64,8 +68,19 @@ static void prepare_msys2_linker_flags(const char ***args, const char **files_to
static bool link_exe(const char *output_file, const char **files_to_link, unsigned file_count) static bool link_exe(const char *output_file, const char **files_to_link, unsigned file_count)
{ {
const char **args = NULL; const char **args = NULL;
vec_add(args, "-o"); #ifdef _MSC_VER
vec_add(args, output_file); if (platform_target.os == OS_TYPE_WIN32)
{
vec_add(args, join_strings((const char* []) {"/out:", output_file}, 2));
}
else
{
#endif
vec_add(args, "-o");
vec_add(args, output_file);
#ifdef _MSC_VER
}
#endif
VECEACH(active_target.link_args, i) VECEACH(active_target.link_args, i)
{ {
vec_add(args, active_target.link_args[i]); vec_add(args, active_target.link_args[i]);
@@ -78,16 +93,43 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
// TODO: properly detect if llvm-lld is available // TODO: properly detect if llvm-lld is available
// TODO: check if running inside MSYS2, it could be done via getting MSYSTEM environment variable // 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 // 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"))
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); // "native" windows
// find paths to library directories.
// ex:
// C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\lib\\x64
// C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\atlmfc\\lib\\x64
// C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\ucrt\\x64
// C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\um\\x64
#ifdef _MSC_VER
PathPair msvc_paths = get_latest_available_vs_path();
PathPair windows_kit_paths = find_winkit_path();
vec_add(args, join_strings((const char* []) { "-libpath:C:", msvc_paths.first }, 2));
vec_add(args, join_strings((const char* []) { "-libpath:C:", msvc_paths.second }, 2));
vec_add(args, join_strings((const char* []) { "-libpath:C:", windows_kit_paths.first }, 2));
vec_add(args, join_strings((const char* []) { "-libpath:C:", windows_kit_paths.second }, 2));
vec_add(args, "-defaultlib:libcmt");
vec_add(args, "-nologo");
add_files(&args, files_to_link, file_count);
#else
error_exit("ERROR - c3c must be compiled with MSVC to target x64-windows\n");
#endif
} }
else else
{ {
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; break;
case OS_TYPE_MACOSX: case OS_TYPE_MACOSX:
add_files(&args, files_to_link, file_count); add_files(&args, files_to_link, file_count);

View File

@@ -22,8 +22,7 @@ void gencontext_begin_module(GenContext *c)
} }
const char *result = scratch_buffer_to_string(); const char *result = scratch_buffer_to_string();
c->ir_filename = strformat("%s.ll", result); c->ir_filename = strformat("%s.ll", result);
// TODO filename should depend on platform. c->object_filename = strformat("%s%s", result, DEFAULT_OBJ_FILE_EXT);
c->object_filename = strformat("%s.o", result);
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context); c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
c->machine = llvm_target_machine_create(); c->machine = llvm_target_machine_create();

View File

@@ -226,12 +226,14 @@ Expr *parse_cond(Context *context)
return decl_expr; return decl_expr;
} }
inline Expr* parse_expr(Context *context) // These used to be explicitly inlined, but that seems to lead to confusing MSVC linker errors.
// They are probably still inlined by the compiler, though I haven't checked.
Expr* parse_expr(Context *context)
{ {
return parse_precedence(context, PREC_ASSIGNMENT); return parse_precedence(context, PREC_ASSIGNMENT);
} }
inline Expr* parse_constant_expr(Context *context) Expr* parse_constant_expr(Context *context)
{ {
return parse_precedence(context, PREC_TERNARY); return parse_precedence(context, PREC_TERNARY);
} }

View File

@@ -989,6 +989,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
{ {
DEBUG_LOG("----Analysing function %s", decl->name); DEBUG_LOG("----Analysing function %s", decl->name);
Type *func_type = sema_analyse_function_signature(context, &decl->func_decl.function_signature, true); Type *func_type = sema_analyse_function_signature(context, &decl->func_decl.function_signature, true);
decl->type = func_type; decl->type = func_type;
if (!func_type) return decl_poison(decl); if (!func_type) return decl_poison(decl);
if (decl->func_decl.type_parent) if (decl->func_decl.type_parent)

View File

@@ -4,7 +4,10 @@
#include "compiler_internal.h" #include "compiler_internal.h"
#if defined(_MSC_VER)
// This isn't standard apparently, so MSVC doesn't have it built in...
typedef long long int ssize_t;
#endif
static inline bool matches_subpath(Path *path_to_check, Path *path_to_find) static inline bool matches_subpath(Path *path_to_check, Path *path_to_find)
{ {

View File

@@ -3,7 +3,13 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include <sys/stat.h> #include <sys/stat.h>
#ifdef _MSC_VER
#define PATH_MAX 260
#else
#include <limits.h> #include <limits.h>
#endif
#include "compiler_internal.h" #include "compiler_internal.h"
#include "../build/build_options.h" #include "../build/build_options.h"
@@ -23,7 +29,11 @@ File *source_file_load(const char *filename, bool *already_loaded)
if (already_loaded) *already_loaded = false; if (already_loaded) *already_loaded = false;
if (!source_files.files) source_files.files = VECNEW(File *, LEXER_FILES_START_CAPACITY); if (!source_files.files) source_files.files = VECNEW(File *, LEXER_FILES_START_CAPACITY);
char *full_path = malloc_arena(PATH_MAX + 1); #ifdef _MSC_VER
char* full_path = malloc_arena(MAX_PATH + 1);
#else
char* full_path = malloc_arena(PATH_MAX + 1);
#endif
if (!realpath(filename, full_path)) if (!realpath(filename, full_path))
{ {
error_exit("Failed to resolve %s", filename); error_exit("Failed to resolve %s", filename);

View File

@@ -45,7 +45,6 @@ int main(int argc, const char *argv[])
UNREACHABLE UNREACHABLE
} }
print_arena_status(); print_arena_status();
free_arena(); free_arena();
return 0; return 0;

1030
src/utils/dirent.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,18 +6,65 @@
#include "common.h" #include "common.h"
#include "errors.h" #include "errors.h"
#include "lib.h" #include "lib.h"
#if PLATFORM_WINDOWS
#include <windows.h>
#endif
#ifndef _MSC_VER
#include <libgen.h> #include <libgen.h>
#include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #else
#include "utils/dirent.h"
#define PATH_MAX 260
// dirname and basename on windows
#include "win_dirname_basename.h"
// copied from https://github.com/kindkaktus/libconfig/commit/d6222551c5c01c326abc99627e151d549e0f0958
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
// copied from https://stackoverflow.com/questions/11238918/s-isreg-macro-undefined
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#endif
#include <errno.h> #include <errno.h>
#include "whereami.h" #include "whereami.h"
#if PLATFORM_WINDOWS #if PLATFORM_WINDOWS
#include <windows.h>
/**
* remove C: drive prefix (C:, D:, etc.) from a path. THIS WON'T WORK WITH D:, ETC.
* If that is an issue, I think dirent will have to be replaced or the dirent
* port in use will have to be replaced.
*/
char* strip_drive_prefix(char* path) {
if ((*path == 'c' || *path == 'C') && path[1] == ':') {
return path + 2; // remove first two characters
}
else if (path[1] == ':' && (path[2] == '/' || path[2] == '\\')) { // I don't *think* a relative path can start with '[char]:/' ? right?
// nothing can be done about this currently
error_exit("Illegal path %s - absolute path must start with /, \\, c:, or C: (file a github issue if this is a problem)");
}
else {
// path is ok
return path;
}
}
#endif #endif
const char* expand_path(const char* path) const char* expand_path(const char* path)
{ {
if (path[0] == '~' && path[1] == '/') if (path[0] == '~' && path[1] == '/')
@@ -147,7 +194,11 @@ void file_find_top_dir()
void file_add_wildcard_files(const char ***files, const char *path, bool recursive) void file_add_wildcard_files(const char ***files, const char *path, bool recursive)
{ {
DIR *dir = opendir(path); #ifdef _MSC_VER
DIR *dir = opendir(strip_drive_prefix(path));
#else
DIR* dir = opendir(path);
#endif
bool path_ends_with_slash = path[strlen(path) - 1] == '/'; bool path_ends_with_slash = path[strlen(path) - 1] == '/';
if (!dir) if (!dir)
{ {

79
src/utils/find_msvc.c Normal file
View File

@@ -0,0 +1,79 @@
#include "utils/common.h"
#ifdef _MSC_VER
#include "utils/find_msvc.h"
#include <stdio.h>
#include "utils/dirent.h"
#define MSVC_BASE_PATH "/Program Files (x86)/Microsoft Visual Studio/"
#define WINKIT_BASE_PATH "/Program Files (x86)/Windows Kits/"
int is_numeric(const struct dirent* ent) {
return atoi(ent->d_name); // don't use this function if you expect a file named "0" ?
}
char* get_highest_ver(char* directory, int (*filter)(const struct dirent*)) {
struct dirent** files;
int num_files = scandir(directory, &files, filter, versionsort);
if (num_files < 0) {
error_exit("ERROR - Failed to autodetect MSVC libpaths\n");
}
char* path_ret = (char*)malloc(260);
strcpy_s(path_ret, 260, files[num_files - 1]->d_name);
for (int i = 0; i < num_files; i++) free(files[i]);
free(files);
return path_ret;
}
/**
* @returns PathPair containing paths to .../MSVC/[version]/lib/x64 and .../MSVC/[v]/atlmfc/lib/x64
*/
PathPair get_latest_available_vs_path() {
char ver_name[16] = "";
char* highest_ver = get_highest_ver(MSVC_BASE_PATH, is_numeric);
strncpy_s(ver_name, 16, highest_ver, 4);
free(highest_ver);
char newpath[260];
snprintf(newpath, 260, "%s%s/BuildTools/VC/Tools/MSVC/", MSVC_BASE_PATH, ver_name);
highest_ver = get_highest_ver(newpath, NULL);
strcat_s(newpath, 260, highest_ver);
free(highest_ver);
PathPair ret = { 0 };
snprintf(ret.first, 260, "%s/lib/x64", newpath);
snprintf(ret.second, 260, "%s/atlmfc/lib/x64", newpath);
return ret;
}
/**
* @returns PathPair containing paths to /Program Files (x86)/Windows Kits/[version]/Lib/[version]/ucrt/x64 and .../[version]/um/x64
*/
PathPair find_winkit_path() {
// windows version
char win_ver_major[16] = "";
char* highest_ver = get_highest_ver(WINKIT_BASE_PATH, is_numeric);
strcpy_s(win_ver_major, 16, highest_ver);
free(highest_ver);
// windows kit version? or something
char newpath[260] = "";
sprintf_s(newpath, 260, "%s%s/Lib/", WINKIT_BASE_PATH, win_ver_major);
highest_ver = get_highest_ver(newpath, NULL);
strcat_s(newpath, 260, highest_ver);
free(highest_ver);
PathPair ret = { 0 };
snprintf(ret.first, 260, "%s/ucrt/x64", newpath);
snprintf(ret.second, 260, "%s/um/x64", newpath);
return ret;
}
#endif //defined(_MSC_VER)

9
src/utils/find_msvc.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
typedef struct {
char first[260];
char second[260];
} PathPair;
PathPair get_latest_available_vs_path();
PathPair find_winkit_path();

View File

@@ -104,6 +104,21 @@ int vasnprintf(char **strp, const char *fmt, va_list args)
return res; return res;
} }
int vasprintf(char** ret, const char* fmt, va_list args) {
int length = _vsnprintf(NULL, 0, fmt, args);
if (length < 0) { // check if _vsnprintf failed
return -1;
}
*ret = malloc(length + 1);
if (!*ret) { // check if malloc failed
return -1;
}
// Write String
_vsnprintf(*ret, length + 1, fmt, args);
(*ret)[length] = '\0'; // make sure there is a null terminator
return length;
}
char *strndup(const char *s, size_t n) char *strndup(const char *s, size_t n)
{ {
n = strnlen(s, n); n = strnlen(s, n);

View File

@@ -2,13 +2,14 @@
// Use of this source code is governed by a LGPLv3.0 // Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include "vmem.h" #include "vmem.h"
#if PLATFORM_POSIX #if PLATFORM_POSIX
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#if PLATFORM_WINDOWS #if defined(WIN32)
#include <Windows.h> #include <Windows.h>
#define COMMIT_PAGE_SIZE 0x10000 #define COMMIT_PAGE_SIZE 0x10000
#endif #endif

View File

@@ -4,6 +4,10 @@
// Code based off Gregory Pakosz's whereami. // Code based off Gregory Pakosz's whereami.
#if defined(WIN32)
#include <windows.h>
#endif
#include "whereami.h" #include "whereami.h"
#include <stdlib.h> #include <stdlib.h>
@@ -32,7 +36,6 @@
#pragma warning(push, 3) #pragma warning(push, 3)
#endif #endif
#include <windows.h>
#include <intrin.h> #include <intrin.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)

View File

@@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// TODO I made these super quickly so they probably have some bugs from cases I didn't think of.
// A better implementation of these functions may be necessary.
char* basename(char* path)
{
size_t len = strlen(path);
size_t lastSlash = 0;
for (size_t i = len - 2; i > 0; i--)
{
if (path[i] == '\\' || path[i] == '/')
{
if (i == len)
{
continue;
}
lastSlash = i;
break;
}
if (i == 0)
{
// according to `man 3 basename` if there is no /, the original path should be returned
char* newStr = (char*)malloc(len);
strcpy(newStr, path);
return newStr;
}
}
size_t newSize = len - lastSlash - 1;
char* newStr = (char*)malloc(newSize);
strncpy(newStr, path + lastSlash + 1, newSize);
return newStr;
}
char* dirname(char* path)
{
size_t len = strlen(path);
size_t lastSlash = 0;
for (size_t i = len - 2; i > 0; i--)
{
if (path[i] == '\\' || path[i] == '/')
{
if (i == len)
{
continue;
}
lastSlash = i;
break;
}
if (i == 0)
{
// according to `man 3 basename` if there is no /, "." should be returned
char* newStr = (char*)malloc(2);
strcpy(newStr, ".");
return newStr;
}
}
// size_t newSize = len - lastSlash - 1;
char* newStr = (char*)malloc(lastSlash);
strncpy(newStr, path, lastSlash);
return newStr;
}

29
windows_build.md Normal file
View File

@@ -0,0 +1,29 @@
# Building and using C3C on windows
Windows support in C3C is currently experimental and unstable. It has many limitations and likely has bugs. With that aside, here's how you can build and use it:
## Compiling LLVM
First, follow the steps outlined here to set up and compile LLVM:
https://llvm.org/docs/GettingStartedVS.html
When running cmake, use the following options to enable all of the libraries needed by C3C:
```
cmake .. -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TARGETS_TO_BUILD="ARM;AArch64;RISCV;WebAssembly;X86" -Thost=x64
```
## Compiling C3C
Clone the C3C github repository and open its directory in visual studio. VS should detect the CMake configuration, allowing you to simply use Build -> Build All to compile C3C. A `c3c.exe` will be placed in `out/build/build`.
## Using C3C on Windows
At this point, you should be able to use C3C normally. For example:
```
/c3c/out/build/build/c3c.exe compile ./hello_world.c3c
```
Note that on windows, linker arguments passed through c3c using `-z` will need to be of the format expected by `lld-link`, which uses MSVC `link.exe`-format arguments rather than the GCC/Clang format.