mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
MSVC compatibility
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -60,3 +60,8 @@ dkms.conf
|
||||
/resources/y.tab.c
|
||||
/resources/y.tab.h
|
||||
/bin/
|
||||
|
||||
#visual studio files
|
||||
.vs/
|
||||
.vscode/
|
||||
out/
|
||||
@@ -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})
|
||||
|
||||
find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_ELF NAMES lldELF.a liblldELF.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})
|
||||
# These don't seem to be reliable on windows.
|
||||
if(UNIX)
|
||||
message(STATUS "using find_library")
|
||||
find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_WASM NAMES lldWasm.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_MINGW NAMES lldMinGW.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS})
|
||||
find_library(LLD_ELF NAMES lldELF.a liblldELF.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_COMMON}
|
||||
${LLD_WASM}
|
||||
@@ -76,6 +79,8 @@ set(lld_libs
|
||||
${LLD_YAML}
|
||||
${LLD_CORE}
|
||||
)
|
||||
message(STATUS "linking to llvm libs ${llvm_libs} ${lld_libs}")
|
||||
endif()
|
||||
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
|
||||
|
||||
add_executable(c3c
|
||||
@@ -107,6 +112,7 @@ add_executable(c3c
|
||||
src/compiler/module.c
|
||||
src/compiler/llvm_codegen.c
|
||||
src/utils/stringutils.c
|
||||
src/utils/find_msvc.c
|
||||
src/compiler/dwarf.h
|
||||
src/compiler/copying.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_wasm.c)
|
||||
|
||||
target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result
|
||||
-Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)
|
||||
|
||||
if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
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
|
||||
"${CMAKE_SOURCE_DIR}/src/")
|
||||
@@ -158,9 +166,18 @@ target_include_directories(c3c_wrappers PRIVATE
|
||||
|
||||
message(STATUS "Found LLD ${lld_libs}")
|
||||
|
||||
target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs})
|
||||
#target_link_libraries(c3c m ${llvm_libs} c3c_wrappers lldCommon lldCore lldCOFF lldWASM lldMinGW lldELF lldDriver lldReaderWriter lldMachO lldYAML)
|
||||
target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs})
|
||||
if(UNIX)
|
||||
message(STATUS "adding unix link params")
|
||||
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 (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILE_ID STREQUAL "GNU")
|
||||
|
||||
15
CMakeSettings.json
Normal file
15
CMakeSettings.json
Normal 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": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <utils/lib.h>
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a LGPLv3.0
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <dirent.h>
|
||||
#else
|
||||
#include "utils/dirent.h"
|
||||
#endif
|
||||
#include "build_internal.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;
|
||||
}
|
||||
#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->pic != PIC_DEFAULT) target->pic = options->pic;
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include "project_creation.h"
|
||||
#include "build_options.h"
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include "compiler_internal.h"
|
||||
#include "parser_internal.h"
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define MAX_OUTPUT_FILES 1000000
|
||||
#define MAX_MODULES 100000
|
||||
@@ -483,7 +485,7 @@ static void target_expand_source_names(BuildTarget *target)
|
||||
|
||||
void compile_target(BuildOptions *options)
|
||||
{
|
||||
init_default_build_target(&active_target, options, "a.out");
|
||||
init_default_build_target(&active_target, options, DEFAULT_EXE);
|
||||
compile();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,13 @@ typedef int32_t ScopeId;
|
||||
#define DEFAULT_EXE "a.out"
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#define DEFAULT_OBJ_FILE_EXT ".obj"
|
||||
#else
|
||||
#define DEFAULT_OBJ_FILE_EXT ".o"
|
||||
#endif
|
||||
|
||||
|
||||
typedef uint32_t SourceLoc;
|
||||
typedef struct
|
||||
{
|
||||
@@ -554,9 +561,9 @@ typedef struct Decl_
|
||||
SourceSpan span;
|
||||
const char *external_name;
|
||||
Ast *docs;
|
||||
DeclKind decl_kind : 6;
|
||||
Visibility visibility : 2;
|
||||
ResolveStatus resolve_status : 2;
|
||||
DeclKind decl_kind : 7;
|
||||
Visibility visibility : 3;
|
||||
ResolveStatus resolve_status : 3;
|
||||
bool is_packed : 1;
|
||||
bool is_opaque : 1;
|
||||
bool needs_additional_pad : 1;
|
||||
|
||||
@@ -295,7 +295,7 @@ typedef enum
|
||||
TYPE_INFO_POINTER,
|
||||
} TypeInfoKind;
|
||||
|
||||
typedef enum
|
||||
typedef enum
|
||||
{
|
||||
TOKEN_INVALID_TOKEN = 0,
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
#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_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);
|
||||
@@ -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)
|
||||
{
|
||||
const char **args = NULL;
|
||||
vec_add(args, "-o");
|
||||
vec_add(args, output_file);
|
||||
#ifdef _MSC_VER
|
||||
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)
|
||||
{
|
||||
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: 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"))
|
||||
if (NULL == getenv("MSYSTEM"))
|
||||
{
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -22,8 +22,7 @@ void gencontext_begin_module(GenContext *c)
|
||||
}
|
||||
const char *result = scratch_buffer_to_string();
|
||||
c->ir_filename = strformat("%s.ll", result);
|
||||
// TODO filename should depend on platform.
|
||||
c->object_filename = strformat("%s.o", result);
|
||||
c->object_filename = strformat("%s%s", result, DEFAULT_OBJ_FILE_EXT);
|
||||
|
||||
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
|
||||
c->machine = llvm_target_machine_create();
|
||||
|
||||
@@ -226,12 +226,14 @@ Expr *parse_cond(Context *context)
|
||||
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);
|
||||
}
|
||||
|
||||
inline Expr* parse_constant_expr(Context *context)
|
||||
Expr* parse_constant_expr(Context *context)
|
||||
{
|
||||
return parse_precedence(context, PREC_TERNARY);
|
||||
}
|
||||
|
||||
@@ -989,6 +989,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
|
||||
{
|
||||
DEBUG_LOG("----Analysing function %s", decl->name);
|
||||
Type *func_type = sema_analyse_function_signature(context, &decl->func_decl.function_signature, true);
|
||||
|
||||
decl->type = func_type;
|
||||
if (!func_type) return decl_poison(decl);
|
||||
if (decl->func_decl.type_parent)
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#include <sys/stat.h>
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define PATH_MAX 260
|
||||
|
||||
#else
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include "compiler_internal.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 (!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))
|
||||
{
|
||||
error_exit("Failed to resolve %s", filename);
|
||||
|
||||
@@ -45,7 +45,6 @@ int main(int argc, const char *argv[])
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
print_arena_status();
|
||||
free_arena();
|
||||
return 0;
|
||||
|
||||
1030
src/utils/dirent.h
Normal file
1030
src/utils/dirent.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,18 +6,65 @@
|
||||
#include "common.h"
|
||||
#include "errors.h"
|
||||
#include "lib.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.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 "whereami.h"
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
const char* expand_path(const char* path)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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] == '/';
|
||||
if (!dir)
|
||||
{
|
||||
|
||||
79
src/utils/find_msvc.c
Normal file
79
src/utils/find_msvc.c
Normal 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
9
src/utils/find_msvc.h
Normal 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();
|
||||
@@ -104,6 +104,21 @@ int vasnprintf(char **strp, const char *fmt, va_list args)
|
||||
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)
|
||||
{
|
||||
n = strnlen(s, n);
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
// Use of this source code is governed by a LGPLv3.0
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "vmem.h"
|
||||
|
||||
#if PLATFORM_POSIX
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if defined(WIN32)
|
||||
#include <Windows.h>
|
||||
#define COMMIT_PAGE_SIZE 0x10000
|
||||
#endif
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
// Code based off Gregory Pakosz's whereami.
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "whereami.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -32,7 +36,6 @@
|
||||
#pragma warning(push, 3)
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
64
src/utils/win_dirname_basename.h
Normal file
64
src/utils/win_dirname_basename.h
Normal 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
29
windows_build.md
Normal 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.
|
||||
Reference in New Issue
Block a user